diff --git a/NorahUniversity/__pycache__/urls.cpython-313.pyc b/NorahUniversity/__pycache__/urls.cpython-313.pyc index f0d7832..0a83457 100644 Binary files a/NorahUniversity/__pycache__/urls.cpython-313.pyc and b/NorahUniversity/__pycache__/urls.cpython-313.pyc differ diff --git a/NorahUniversity/settings.py b/NorahUniversity/settings.py index ed4604f..58cb627 100644 --- a/NorahUniversity/settings.py +++ b/NorahUniversity/settings.py @@ -471,7 +471,7 @@ CKEDITOR_5_CONFIGS = { # Define a constant in settings.py to specify file upload permissions CKEDITOR_5_FILE_UPLOAD_PERMISSION = ( "staff" # Possible values: "staff", "authenticated", "any" - +) @@ -479,7 +479,7 @@ from django.contrib.messages import constants as messages MESSAGE_TAGS = { messages.ERROR: 'danger', } -) + # Custom User Model AUTH_USER_MODEL = "recruitment.CustomUser" diff --git a/apply_all_translations.py b/apply_all_translations.py deleted file mode 100644 index 582b76f..0000000 --- a/apply_all_translations.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to apply all batch translations to the main django.po file -""" - -import re - -def apply_all_translations(): - """ - Apply all translations to the main django.po file - """ - # All translations from batches 02-35 - translations = { - "The date and time this notification is scheduled to be sent.": "التاريخ والوقت المحدد لإرسال هذا الإشعار.", - "Send Attempts": "محاولات الإرسال", - "Failed to start the job posting process. Please try again.": "فشل في بدء عملية نشر الوظيفة. يرجى المحاولة مرة أخرى.", - "You don't have permission to view this page.": "ليس لديك إذن لعرض هذه الصفحة.", - "Account Inactive": "الحساب غير نشط", - "Princess Nourah bint Abdulrahman University": "جامعة الأميرة نورة بنت عبدالرحمن", - "Manage your personal details and security.": "إدارة تفاصيلك الشخصية والأمان.", - "Primary": "أساسي", - "Verified": "موثق", - "Unverified": "غير موثق", - "Make Primary": "جعل أساسي", - "Remove": "إزالة", - "Add Email Address": "إضافة عنوان بريد إلكتروني", - "Hello,": "مرحباً،", - "Confirm My KAAUH ATS Email": "تأكيد بريدي الإلكتروني في نظام توظيف جامعة نورة", - "Alternatively, copy and paste this link into your browser:": "بدلاً من ذلك، انسخ والصق هذا الرابط في متصفحك:", - "Password Reset Request": "طلب إعادة تعيين كلمة المرور", - "Click Here to Reset Your Password": "اضغط هنا لإعادة تعيين كلمة المرور", - "This link is only valid for a limited time.": "هذا الرابط صالح لفترة محدودة فقط.", - "Thank you,": "شكراً لك،", - "KAAUH ATS Team": "فريق نظام توظيف جامعة نورة", - "Confirm Email Address": "تأكيد عنوان البريد الإلكتروني", - "Account Verification": "التحقق من الحساب", - "Verify your email to secure your account and unlock full features.": "تحقق من بريدك الإلكتروني لتأمين حسابك وإلغاء قفل جميع الميزات.", - "Confirm Your Email Address": "تأكيد عنوان بريدك الإلكتروني", - "Verification Failed": "فشل التحقق", - "The email confirmation link is expired or invalid.": "رابط تأكيد البريد الإلكتروني منتهي الصلاحية أو غير صالح.", - "Keep me signed in": "ابق مسجلاً للدخول", - "Return to Profile": "العودة إلى الملف الشخصي", - "Enter your e-mail address to reset your password.": "أدخل عنوان بريدك الإلكتروني لإعادة تعيين كلمة المرور.", - "Remember your password?": "تتذكر كلمة المرور؟", - "Log In": "تسجيل الدخول", - "Password Reset Sent": "تم إرسال إعادة تعيين كلمة المرور", - "Return to Login": "العودة إلى تسجيل الدخول", - "Please enter your new password below.": "يرجى إدخال كلمة المرور الجديدة أدناه.", - "Logout": "تسجيل الخروج", - "Yes": "نعم", - "No": "لا", - "Success": "نجح", - "Login": "تسجيل الدخول", - "Link": "ربط", - "Clear": "مسح", - "All": "الكل", - "Comments": "التعليقات", - "Save": "حفظ", - "Notes": "ملاحظات", - "New": "جديد", - "Users": "المستخدمون", - "Filter": "تصفية", - "Home": "الرئيسية", - "Username": "اسم المستخدم", - "Modified": "تم التعديل", - "Unlink": "فك الربط", - "Group": "تجميع", - "Export": "تصدير", - "Import": "استيراد", - "None": "لا شيء", - "Add": "إضافة", - "True": "صحيح", - "False": "خطأ", - } - - main_po_file = "locale/ar/LC_MESSAGES/django.po" - - # Read the main django.po file - with open(main_po_file, 'r', encoding='utf-8') as f: - main_content = f.read() - - # Apply translations to main file - updated_content = main_content - applied_count = 0 - - for english, arabic in translations.items(): - # Pattern to find msgid followed by empty msgstr - pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""' - replacement = rf'\1 "{arabic}"' - - if re.search(pattern, updated_content): - updated_content = re.sub(pattern, replacement, updated_content) - applied_count += 1 - print(f"✓ Applied: '{english}' -> '{arabic}'") - else: - print(f"✗ Not found: '{english}'") - - # Write updated content back to main file - with open(main_po_file, 'w', encoding='utf-8') as f: - f.write(updated_content) - - print(f"\nApplied {applied_count} translations to {main_po_file}") - return applied_count - -def main(): - """Main function to apply all translations""" - print("Applying all batch translations to main django.po file...") - applied_count = apply_all_translations() - - if applied_count > 0: - print(f"\n✅ Successfully applied {applied_count} translations!") - print("Next steps:") - print("1. Run: python manage.py compilemessages") - print("2. Test the translations in the application") - else: - print("\n❌ No translations were applied.") - -if __name__ == "__main__": - main() diff --git a/apply_batch_translations.py b/apply_batch_translations.py deleted file mode 100644 index 6249bdd..0000000 --- a/apply_batch_translations.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to apply completed batch translations back to the main django.po file -""" - -import re - -def apply_batch_to_main_po(batch_file_path, main_po_path): - """ - Apply translations from a completed batch file to the main django.po file - """ - # Read the completed batch file - with open(batch_file_path, 'r', encoding='utf-8') as f: - batch_content = f.read() - - # Extract translations from batch file - translations = {} - current_msgid = None - - lines = batch_content.split('\n') - i = 0 - while i < len(lines): - line = lines[i].strip() - if line.startswith('msgid: "'): - current_msgid = line[7:-1] # Extract msgid content - # Look for the Arabic translation line (next non-empty line after "Arabic Translation:") - j = i + 1 - while j < len(lines) and not lines[j].strip().startswith('msgstr: "'): - j += 1 - if j < len(lines) and lines[j].strip().startswith('msgstr: "'): - translation = lines[j].strip()[8:-1] # Extract msgstr content - if translation and current_msgid and translation != '""': # Only add non-empty translations - translations[current_msgid] = translation - print(f"Extracted: '{current_msgid}' -> '{translation}'") - current_msgid = None - i += 1 - - print(f"Found {len(translations)} translations to apply") - - # Read the main django.po file - with open(main_po_path, 'r', encoding='utf-8') as f: - main_content = f.read() - - # Apply translations to main file - updated_content = main_content - applied_count = 0 - - for english, arabic in translations.items(): - # Pattern to find msgid followed by empty msgstr - pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""' - replacement = rf'\1 "{arabic}"' - - if re.search(pattern, updated_content): - updated_content = re.sub(pattern, replacement, updated_content) - applied_count += 1 - print(f"✓ Applied: '{english}' -> '{arabic}'") - else: - print(f"✗ Not found: '{english}'") - - # Write updated content back to main file - with open(main_po_path, 'w', encoding='utf-8') as f: - f.write(updated_content) - - print(f"\nApplied {applied_count} translations to {main_po_path}") - return applied_count - -def main(): - """Main function to apply batch 01 translations""" - batch_file = "translation_batch_01_completed.txt" - main_po_file = "locale/ar/LC_MESSAGES/django.po" - - print("Applying Batch 01 translations to main django.po file...") - applied_count = apply_batch_to_main_po(batch_file, main_po_file) - - if applied_count > 0: - print(f"\n✅ Successfully applied {applied_count} translations!") - print("Next steps:") - print("1. Run: python manage.py compilemessages") - print("2. Test the translations in the application") - print("3. Continue with the next batch") - else: - print("\n❌ No translations were applied. Please check the batch file format.") - -if __name__ == "__main__": - main() diff --git a/apply_translations_direct.py b/apply_translations_direct.py deleted file mode 100644 index 1c40a2b..0000000 --- a/apply_translations_direct.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to directly apply Arabic translations to the main django.po file -""" - -import re - -def apply_translations_direct(): - """ - Apply translations directly to the main django.po file - """ - # Arabic translations for batch 01 - translations = { - "Website": "الموقع الإلكتروني", - "Admin Notes": "ملاحظات المسؤول", - "Save Assignment": "حفظ التكليف", - "Assignment": "التكليف", - "Expires At": "ينتهي في", - "Access Token": "رمز الوصول", - "Subject": "الموضوع", - "Recipients": "المستلمون", - "Internal staff involved in the recruitment process for this job": "الموظفون الداخليون المشاركون في عملية التوظيف لهذه الوظيفة", - "External Participant": "مشارك خارجي", - "External participants involved in the recruitment process for this job": "المشاركون الخارجيون المشاركون في عملية التوظيف لهذه الوظيفة", - "Reason for canceling the job posting": "سبب إلغاء نشر الوظيفة", - "Name of person who cancelled this job": "اسم الشخص الذي ألغى هذه الوظيفة", - "Hired": "تم التوظيف", - "Author": "المؤلف", - "Endpoint URL for sending candidate data (for outbound sync)": "عنوان URL لنقطة النهاية لإرسال بيانات المرشح (للمزامنة الصادرة)", - "HTTP method for outbound sync requests": "طريقة HTTP لطلبات المزامنة الصادرة", - "HTTP method for connection testing": "طريقة HTTP لاختبار الاتصال", - "Custom Headers": "رؤوس مخصصة", - "JSON object with custom HTTP headers for sync requests": "كائن JSON يحتوي على رؤوس HTTP مخصصة لطلبات المزامنة", - "Supports Outbound Sync": "يدعم المزامنة الصادرة", - "Whether this source supports receiving candidate data from ATS": "ما إذا كان هذا المصدر يدعم استقبال بيانات المرشح من نظام تتبع المتقدمين", - "Expired": "منتهي الصلاحية", - "Maximum candidates agency can submit for this job": "الحد الأقصى للمرشحين الذين يمكن للوكالة تقديمهم لهذه الوظيفة" - } - - main_po_file = "locale/ar/LC_MESSAGES/django.po" - - # Read the main django.po file - with open(main_po_file, 'r', encoding='utf-8') as f: - main_content = f.read() - - # Apply translations to main file - updated_content = main_content - applied_count = 0 - - for english, arabic in translations.items(): - # Pattern to find msgid followed by empty msgstr - pattern = rf'(msgid "{re.escape(english)}"\s*\nmsgstr) ""' - replacement = rf'\1 "{arabic}"' - - if re.search(pattern, updated_content): - updated_content = re.sub(pattern, replacement, updated_content) - applied_count += 1 - print(f"✓ Applied: '{english}' -> '{arabic}'") - else: - print(f"✗ Not found: '{english}'") - - # Write updated content back to main file - with open(main_po_file, 'w', encoding='utf-8') as f: - f.write(updated_content) - - print(f"\nApplied {applied_count} translations to {main_po_file}") - return applied_count - -def main(): - """Main function to apply batch 01 translations""" - print("Applying Batch 01 translations directly to main django.po file...") - applied_count = apply_translations_direct() - - if applied_count > 0: - print(f"\n✅ Successfully applied {applied_count} translations!") - print("Next steps:") - print("1. Run: python manage.py compilemessages") - print("2. Test the translations in the application") - print("3. Continue with the next batch") - else: - print("\n❌ No translations were applied.") - -if __name__ == "__main__": - main() diff --git a/find_empty_translations.py b/find_empty_translations.py deleted file mode 100644 index ca0ea4d..0000000 --- a/find_empty_translations.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to find empty msgstr entries in django.po file and organize them into batches -for systematic Arabic translation work. -""" - -import re -import os -from typing import List, Tuple - -def find_empty_translations(po_file_path: str) -> List[Tuple[int, str, str]]: - """ - Find all entries with empty msgstr in the django.po file. - - Returns: - List of tuples: (line_number, msgid, context_before) - """ - empty_translations = [] - - with open(po_file_path, 'r', encoding='utf-8') as file: - lines = file.readlines() - - i = 0 - while i < len(lines): - line = lines[i].strip() - - # Look for msgid - if line.startswith('msgid '): - msgid = line[7:-1] # Remove 'msgid "' and ending '"' - - # Check next few lines for msgstr - j = i + 1 - msgstr_found = False - msgstr_empty = False - - while j < len(lines) and j < i + 5: # Look ahead max 5 lines - next_line = lines[j].strip() - - if next_line.startswith('msgstr '): - msgstr_found = True - if next_line == 'msgstr ""': - msgstr_empty = True - break - elif next_line.startswith('msgid ') or next_line.startswith('#'): - # Found next entry or comment, no msgstr for current msgid - break - j += 1 - - if msgstr_found and msgstr_empty: - # Get context (previous 2-3 lines) - context_start = max(0, i - 3) - context = ''.join(lines[context_start:i]) - empty_translations.append((i + 1, msgid, context)) - - i = j # Skip to after msgstr - else: - i += 1 - - return empty_translations - -def create_batch_files(empty_translations: List[Tuple[int, str, str]], batch_size: int = 25): - """ - Create batch files with empty translations for systematic work. - """ - total_batches = (len(empty_translations) + batch_size - 1) // batch_size - - print(f"Found {len(empty_translations)} empty translations") - print(f"Creating {total_batches} batches of ~{batch_size} translations each") - - for batch_num in range(total_batches): - start_idx = batch_num * batch_size - end_idx = min(start_idx + batch_size, len(empty_translations)) - batch_translations = empty_translations[start_idx:end_idx] - - batch_filename = f"translation_batch_{batch_num + 1:02d}.txt" - - with open(batch_filename, 'w', encoding='utf-8') as batch_file: - batch_file.write(f"=== TRANSLATION BATCH {batch_num + 1:02d} ===\n") - batch_file.write(f"Translations {start_idx + 1}-{end_idx} of {len(empty_translations)}\n") - batch_file.write("=" * 60 + "\n\n") - - for line_num, msgid, context in batch_translations: - batch_file.write(f"Line {line_num}:\n") - batch_file.write(f"msgid: \"{msgid}\"\n") - batch_file.write(f"msgstr: \"\"\n") - batch_file.write(f"\nArabic Translation: \n") - batch_file.write(f"msgstr: \"\"\n") - batch_file.write("-" * 40 + "\n\n") - - print(f"Created {batch_filename} with {len(batch_translations)} translations") - -def create_summary_report(empty_translations: List[Tuple[int, str, str]]): - """ - Create a summary report of all empty translations. - """ - with open("empty_translations_summary.txt", 'w', encoding='utf-8') as report: - report.write("EMPTY TRANSLATIONS SUMMARY REPORT\n") - report.write("=" * 50 + "\n\n") - report.write(f"Total empty translations: {len(empty_translations)}\n\n") - - # Group by type/pattern for better organization - ui_elements = [] - form_fields = [] - messages = [] - navigation = [] - other = [] - - for line_num, msgid, context in empty_translations: - msgid_lower = msgid.lower() - - if any(word in msgid_lower for word in ['button', 'btn', 'click', 'select']): - ui_elements.append((line_num, msgid)) - elif any(word in msgid_lower for word in ['field', 'form', 'input', 'enter']): - form_fields.append((line_num, msgid)) - elif any(word in msgid_lower for word in ['error', 'success', 'warning', 'message']): - messages.append((line_num, msgid)) - elif any(word in msgid_lower for word in ['menu', 'nav', 'page', 'dashboard']): - navigation.append((line_num, msgid)) - else: - other.append((line_num, msgid)) - - report.write(f"UI Elements (Buttons, Links): {len(ui_elements)}\n") - report.write(f"Form Fields & Inputs: {len(form_fields)}\n") - report.write(f"Messages (Error/Success/Warning): {len(messages)}\n") - report.write(f"Navigation & Pages: {len(navigation)}\n") - report.write(f"Other: {len(other)}\n\n") - - report.write("SAMPLE ENTRIES:\n") - report.write("-" * 30 + "\n") - - for category, name, sample_count in [ - (ui_elements, "UI Elements", 5), - (form_fields, "Form Fields", 5), - (messages, "Messages", 5), - (navigation, "Navigation", 5), - (other, "Other", 5) - ]: - if category: - report.write(f"\n{name} (showing first {min(len(category), sample_count)}):\n") - for line_num, msgid in category[:sample_count]: - report.write(f" Line {line_num}: \"{msgid}\"\n") - -def main(): - """Main function to process the django.po file.""" - po_file_path = "locale/ar/LC_MESSAGES/django.po" - - if not os.path.exists(po_file_path): - print(f"Error: {po_file_path} not found!") - return - - print("Scanning for empty translations...") - empty_translations = find_empty_translations(po_file_path) - - if not empty_translations: - print("No empty translations found! All msgstr entries have translations.") - return - - # Create batch files - create_batch_files(empty_translations, batch_size=25) - - # Create summary report - create_summary_report(empty_translations) - - print(f"\nProcess completed!") - print(f"Check the generated batch files: translation_batch_*.txt") - print(f"Summary report: empty_translations_summary.txt") - print(f"\nNext steps:") - print(f"1. Work through each batch file systematically") - print(f"2. Add Arabic translations to each empty msgstr") - print(f"3. Update the main django.po file with completed translations") - -if __name__ == "__main__": - main() diff --git a/fix_po_duplicates.py b/fix_po_duplicates.py deleted file mode 100644 index c51f1d2..0000000 --- a/fix_po_duplicates.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python3 -""" -Fix duplicate message definitions in .po files -""" - -import re -import os - -def fix_po_duplicates(po_file): - """Remove duplicate message definitions from a .po file""" - - print(f"Processing {po_file}...") - - with open(po_file, 'r', encoding='utf-8') as f: - content = f.read() - - # Split into entries - entries = [] - current_entry = [] - lines = content.split('\n') - - i = 0 - while i < len(lines): - line = lines[i] - - if line.startswith('msgid '): - # Start of new entry - if current_entry: - entries.append('\n'.join(current_entry)) - current_entry = [line] - elif line.startswith('msgstr ') and current_entry: - # End of entry - current_entry.append(line) - entries.append('\n'.join(current_entry)) - current_entry = [] - else: - if current_entry: - current_entry.append(line) - - i += 1 - - # Add the last entry if it exists - if current_entry: - entries.append('\n'.join(current_entry)) - - # Remove duplicates, keeping the first occurrence - seen_msgids = set() - unique_entries = [] - - for entry in entries: - # Extract msgid - msgid_match = re.search(r'msgid\s+"([^"]*)"', entry) - if msgid_match: - msgid = msgid_match.group(1) - if msgid not in seen_msgids: - seen_msgids.add(msgid) - unique_entries.append(entry) - else: - print(f" Removing duplicate: {msgid}") - else: - # Header or other entry, keep it - unique_entries.append(entry) - - # Rebuild content - new_content = '\n\n'.join(unique_entries) - - # Write back to file - with open(po_file, 'w', encoding='utf-8') as f: - f.write(new_content) - - print(f" Fixed {po_file} - removed {len(entries) - len(unique_entries)} duplicates") - -def main(): - """Fix duplicates in both English and Arabic .po files""" - - po_files = [ - 'locale/ar/LC_MESSAGES/django.po', - 'locale/en/LC_MESSAGES/django.po' - ] - - for po_file in po_files: - if os.path.exists(po_file): - fix_po_duplicates(po_file) - else: - print(f"File not found: {po_file}") - - print("\n✅ Duplicate fixing completed!") - print("Now run: python manage.py compilemessages") - -if __name__ == "__main__": - main() diff --git a/recruitment/__pycache__/admin.cpython-313.pyc b/recruitment/__pycache__/admin.cpython-313.pyc index f2b8f47..efdeced 100644 Binary files a/recruitment/__pycache__/admin.cpython-313.pyc and b/recruitment/__pycache__/admin.cpython-313.pyc differ diff --git a/recruitment/__pycache__/forms.cpython-313.pyc b/recruitment/__pycache__/forms.cpython-313.pyc index f3e252a..20fd6a9 100644 Binary files a/recruitment/__pycache__/forms.cpython-313.pyc and b/recruitment/__pycache__/forms.cpython-313.pyc differ diff --git a/recruitment/__pycache__/models.cpython-313.pyc b/recruitment/__pycache__/models.cpython-313.pyc index 8c49484..aeceeb2 100644 Binary files a/recruitment/__pycache__/models.cpython-313.pyc and b/recruitment/__pycache__/models.cpython-313.pyc differ diff --git a/recruitment/__pycache__/serializers.cpython-313.pyc b/recruitment/__pycache__/serializers.cpython-313.pyc index 867ca3a..7bef3a1 100644 Binary files a/recruitment/__pycache__/serializers.cpython-313.pyc and b/recruitment/__pycache__/serializers.cpython-313.pyc differ diff --git a/recruitment/__pycache__/signals.cpython-313.pyc b/recruitment/__pycache__/signals.cpython-313.pyc index df7396c..f70295e 100644 Binary files a/recruitment/__pycache__/signals.cpython-313.pyc and b/recruitment/__pycache__/signals.cpython-313.pyc differ diff --git a/recruitment/__pycache__/views.cpython-313.pyc b/recruitment/__pycache__/views.cpython-313.pyc index 3d108b9..17e6e18 100644 Binary files a/recruitment/__pycache__/views.cpython-313.pyc and b/recruitment/__pycache__/views.cpython-313.pyc differ diff --git a/recruitment/__pycache__/views_frontend.cpython-313.pyc b/recruitment/__pycache__/views_frontend.cpython-313.pyc index 0f82cce..444d815 100644 Binary files a/recruitment/__pycache__/views_frontend.cpython-313.pyc and b/recruitment/__pycache__/views_frontend.cpython-313.pyc differ diff --git a/recruitment/forms.py b/recruitment/forms.py index 9e23101..67e3ee1 100644 --- a/recruitment/forms.py +++ b/recruitment/forms.py @@ -1469,8 +1469,8 @@ class ParticipantsForm(forms.ModelForm): } -# class ParticipantsSelectForm(forms.ModelForm): -# """Form for selecting Participants""" +class ParticipantsSelectForm(forms.ModelForm): + """Form for selecting Participants""" participants = forms.ModelMultipleChoiceField( queryset=Participants.objects.all(), @@ -1863,4 +1863,169 @@ class OnsiteMeetingForm(forms.ModelForm): 'location': forms.TextInput(attrs={'placeholder': 'Physical location', 'class': 'form-control'}), 'timezone': forms.TextInput(attrs={'class': 'form-control'}), 'status': forms.Select(attrs={'class': 'form-control'}), - } \ No newline at end of file + } + + +class MessageForm(forms.ModelForm): + """Form for creating and editing messages between users""" + + class Meta: + model = Message + fields = ["recipient", "job", "subject", "content", "message_type"] + widgets = { + "recipient": forms.Select( + attrs={"class": "form-select", "placeholder": "Select recipient"} + ), + "job": forms.Select( + attrs={"class": "form-select", "placeholder": "Select job (optional)"} + ), + "subject": forms.TextInput( + attrs={ + "class": "form-control", + "placeholder": "Enter message subject", + "required": True, + } + ), + "content": forms.Textarea( + attrs={ + "class": "form-control", + "rows": 6, + "placeholder": "Enter your message here...", + "required": True, + } + ), + "message_type": forms.Select(attrs={"class": "form-select"}), + } + labels = { + "recipient": _("Recipient"), + "job": _("Related Job"), + "subject": _("Subject"), + "content": _("Message"), + "message_type": _("Message Type"), + } + + def __init__(self, user, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = user + self.helper = FormHelper() + self.helper.form_method = "post" + self.helper.form_class = "g-3" + + # Filter job options based on user type + self._filter_job_field() + + # Filter recipient options based on user type + self._filter_recipient_field() + + self.helper.layout = Layout( + Row( + Column("recipient", css_class="col-md-6"), + Column("job", css_class="col-md-6"), + css_class="g-3 mb-3", + ), + Field("subject", css_class="form-control"), + Field("message_type", css_class="form-control"), + Field("content", css_class="form-control"), + Div( + Submit("submit", _("Send Message"), css_class="btn btn-main-action"), + css_class="col-12 mt-4", + ), + ) + + def _filter_job_field(self): + """Filter job options based on user type""" + if self.user.user_type == "agency": + # Agency users can only see jobs assigned to their agency + self.fields["job"].queryset = JobPosting.objects.filter( + hiring_agency__user=self.user, + status="ACTIVE" + ).order_by("-created_at") + elif self.user.user_type == "candidate": + # Candidates can only see jobs they applied for + self.fields["job"].queryset = JobPosting.objects.filter( + candidates__user=self.user + ).distinct().order_by("-created_at") + else: + # Staff can see all jobs + self.fields["job"].queryset = JobPosting.objects.filter( + status="ACTIVE" + ).order_by("-created_at") + + def _filter_recipient_field(self): + """Filter recipient options based on user type""" + if self.user.user_type == "staff": + # Staff can message anyone + self.fields["recipient"].queryset = User.objects.all().order_by("username") + elif self.user.user_type == "agency": + # Agency can message staff and their candidates + from django.db.models import Q + self.fields["recipient"].queryset = User.objects.filter( + Q(user_type="staff") | + Q(candidate_profile__job__hiring_agency__user=self.user) + ).distinct().order_by("username") + elif self.user.user_type == "candidate": + # Candidates can only message staff + self.fields["recipient"].queryset = User.objects.filter( + user_type="staff" + ).order_by("username") + + def clean(self): + """Validate message form data""" + cleaned_data = super().clean() + + job = cleaned_data.get("job") + recipient = cleaned_data.get("recipient") + + # If job is selected but no recipient, auto-assign to job.assigned_to + if job and not recipient: + if job.assigned_to: + cleaned_data["recipient"] = job.assigned_to + # Set message type to job_related + cleaned_data["message_type"] = Message.MessageType.JOB_RELATED + else: + raise forms.ValidationError( + _("Selected job is not assigned to any user. Please assign the job first.") + ) + + # Validate messaging permissions + if self.user and cleaned_data.get("recipient"): + self._validate_messaging_permissions(cleaned_data) + + return cleaned_data + + def _validate_messaging_permissions(self, cleaned_data): + """Validate if user can message the recipient""" + recipient = cleaned_data.get("recipient") + job = cleaned_data.get("job") + + # Staff can message anyone + if self.user.user_type == "staff": + return + + # Agency users validation + if self.user.user_type == "agency": + if recipient.user_type not in ["staff", "candidate"]: + raise forms.ValidationError( + _("Agencies can only message staff or candidates.") + ) + + # If messaging a candidate, ensure candidate is from their agency + if recipient.user_type == "candidate" and job: + if not job.hiring_agency.filter(user=self.user).exists(): + raise forms.ValidationError( + _("You can only message candidates from your assigned jobs.") + ) + + # Candidate users validation + if self.user.user_type == "candidate": + if recipient.user_type != "staff": + raise forms.ValidationError( + _("Candidates can only message staff.") + ) + + # If job-related, ensure candidate applied for the job + if job: + if not Candidate.objects.filter(job=job, user=self.user).exists(): + raise forms.ValidationError( + _("You can only message about jobs you have applied for.") + ) diff --git a/recruitment/migrations/0001_initial.py b/recruitment/migrations/0001_initial.py index 68d8fc2..2e786ed 100644 --- a/recruitment/migrations/0001_initial.py +++ b/recruitment/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.6 on 2025-11-10 14:13 +# Generated by Django 5.2.6 on 2025-11-13 13:12 import django.contrib.auth.models import django.contrib.auth.validators @@ -19,6 +19,7 @@ class Migration(migrations.Migration): dependencies = [ ('auth', '0012_alter_user_first_name_max_length'), + ('contenttypes', '0002_remove_content_type_name'), ] operations = [ @@ -47,6 +48,24 @@ class Migration(migrations.Migration): 'ordering': ['order'], }, ), + migrations.CreateModel( + name='OnsiteMeeting', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), + ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), + ('topic', models.CharField(max_length=255, verbose_name='Topic')), + ('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')), + ('duration', models.PositiveIntegerField(verbose_name='Duration')), + ('timezone', models.CharField(max_length=50, verbose_name='Timezone')), + ('location', models.CharField(blank=True, null=True)), + ('status', models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status')), + ], + options={ + 'abstract': False, + }, + ), migrations.CreateModel( name='Participants', fields=[ @@ -145,51 +164,6 @@ class Migration(migrations.Migration): ('objects', django.contrib.auth.models.UserManager()), ], ), - migrations.CreateModel( - name='Application', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), - ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), - ('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')), - ('cover_letter', models.FileField(blank=True, null=True, upload_to='cover_letters/', verbose_name='Cover Letter')), - ('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')), - ('parsed_summary', models.TextField(blank=True, verbose_name='Parsed Summary')), - ('applied', models.BooleanField(default=False, verbose_name='Applied')), - ('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Offer', 'Offer'), ('Hired', 'Hired'), ('Rejected', 'Rejected')], db_index=True, default='Applied', max_length=20, verbose_name='Stage')), - ('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=20, null=True, verbose_name='Applicant Status')), - ('exam_date', models.DateTimeField(blank=True, null=True, verbose_name='Exam Date')), - ('exam_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Exam Status')), - ('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Interview Date')), - ('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Interview Status')), - ('offer_date', models.DateField(blank=True, null=True, verbose_name='Offer Date')), - ('offer_status', models.CharField(blank=True, choices=[('Accepted', 'Accepted'), ('Rejected', 'Rejected'), ('Pending', 'Pending')], max_length=20, null=True, verbose_name='Offer Status')), - ('hired_date', models.DateField(blank=True, null=True, verbose_name='Hired Date')), - ('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')), - ('ai_analysis_data', models.JSONField(blank=True, default=dict, help_text='Full JSON output from the resume scoring model.', null=True, verbose_name='AI Analysis Data')), - ('retry', models.SmallIntegerField(default=3, verbose_name='Resume Parsing Retry')), - ('hiring_source', models.CharField(blank=True, choices=[('Public', 'Public'), ('Internal', 'Internal'), ('Agency', 'Agency')], default='Public', max_length=255, null=True, verbose_name='Hiring Source')), - ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='application_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')), - ], - options={ - 'verbose_name': 'Application', - 'verbose_name_plural': 'Applications', - }, - ), - migrations.CreateModel( - name='Candidate', - fields=[ - ], - options={ - 'verbose_name': 'Candidate (Legacy)', - 'verbose_name_plural': 'Candidates (Legacy)', - 'proxy': True, - 'indexes': [], - 'constraints': [], - }, - bases=('recruitment.application',), - ), migrations.CreateModel( name='FormField', fields=[ @@ -281,10 +255,37 @@ class Migration(migrations.Migration): 'ordering': ['name'], }, ), - migrations.AddField( - model_name='application', - name='hiring_agency', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='recruitment.hiringagency', verbose_name='Hiring Agency'), + migrations.CreateModel( + name='Application', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), + ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), + ('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')), + ('cover_letter', models.FileField(blank=True, null=True, upload_to='cover_letters/', verbose_name='Cover Letter')), + ('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')), + ('parsed_summary', models.TextField(blank=True, verbose_name='Parsed Summary')), + ('applied', models.BooleanField(default=False, verbose_name='Applied')), + ('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Offer', 'Offer'), ('Hired', 'Hired'), ('Rejected', 'Rejected')], db_index=True, default='Applied', max_length=20, verbose_name='Stage')), + ('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=20, null=True, verbose_name='Applicant Status')), + ('exam_date', models.DateTimeField(blank=True, null=True, verbose_name='Exam Date')), + ('exam_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Exam Status')), + ('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Interview Date')), + ('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Interview Status')), + ('offer_date', models.DateField(blank=True, null=True, verbose_name='Offer Date')), + ('offer_status', models.CharField(blank=True, choices=[('Accepted', 'Accepted'), ('Rejected', 'Rejected'), ('Pending', 'Pending')], max_length=20, null=True, verbose_name='Offer Status')), + ('hired_date', models.DateField(blank=True, null=True, verbose_name='Hired Date')), + ('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')), + ('ai_analysis_data', models.JSONField(blank=True, default=dict, help_text='Full JSON output from the resume scoring model.', null=True, verbose_name='AI Analysis Data')), + ('retry', models.SmallIntegerField(default=3, verbose_name='Resume Parsing Retry')), + ('hiring_source', models.CharField(blank=True, choices=[('Public', 'Public'), ('Internal', 'Internal'), ('Agency', 'Agency')], default='Public', max_length=255, null=True, verbose_name='Hiring Source')), + ('hiring_agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='recruitment.hiringagency', verbose_name='Hiring Agency')), + ], + options={ + 'verbose_name': 'Application', + 'verbose_name_plural': 'Applications', + }, ), migrations.CreateModel( name='JobPosting', @@ -327,8 +328,6 @@ class Migration(migrations.Migration): ('cancelled_at', models.DateTimeField(blank=True, null=True)), ('assigned_to', models.ForeignKey(blank=True, help_text='The user who has been assigned to this job', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_jobs', to=settings.AUTH_USER_MODEL, verbose_name='Assigned To')), ('hiring_agency', models.ManyToManyField(blank=True, help_text='External agency responsible for sourcing candidates for this role', related_name='jobs', to='recruitment.hiringagency', verbose_name='Hiring Agency')), - ('users', models.ManyToManyField(blank=True, help_text='Internal staff involved in the recruitment process for this job', related_name='jobs_assigned', to=settings.AUTH_USER_MODEL, verbose_name='Internal Participant')), - ('participants', models.ManyToManyField(blank=True, help_text='External participants involved in the recruitment process for this job', related_name='jobs_participating', to='recruitment.participants', verbose_name='External Participant')), ('source', models.ForeignKey(blank=True, help_text='The system or channel from which this job posting originated or was first published.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='job_postings', to='recruitment.source')), ], options={ @@ -344,6 +343,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), + ('interview_type', models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type')), ('start_date', models.DateField(db_index=True, verbose_name='Start Date')), ('end_date', models.DateField(db_index=True, verbose_name='End Date')), ('working_days', models.JSONField(verbose_name='Working Days')), @@ -353,7 +353,7 @@ class Migration(migrations.Migration): ('break_end_time', models.TimeField(blank=True, null=True, verbose_name='Break End Time')), ('interview_duration', models.PositiveIntegerField(verbose_name='Interview Duration (minutes)')), ('buffer_time', models.PositiveIntegerField(default=0, verbose_name='Buffer Time (minutes)')), - ('candidates', models.ManyToManyField(blank=True, null=True, related_name='interview_schedules', to='recruitment.application')), + ('applications', models.ManyToManyField(blank=True, null=True, related_name='interview_schedules', to='recruitment.application')), ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_schedules', to='recruitment.jobposting')), ], @@ -441,6 +441,7 @@ class Migration(migrations.Migration): ('address', models.TextField(blank=True, null=True, verbose_name='Address')), ('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')), ('linkedin_profile', models.URLField(blank=True, null=True, verbose_name='LinkedIn Profile URL')), + ('agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency')), ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')), ], options={ @@ -448,25 +449,6 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'People', }, ), - migrations.CreateModel( - name='Document', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), - ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), - ('file', models.FileField(upload_to='candidate_documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File')), - ('document_type', models.CharField(choices=[('resume', 'Resume'), ('cover_letter', 'Cover Letter'), ('certificate', 'Certificate'), ('id_document', 'ID Document'), ('passport', 'Passport'), ('education', 'Education Document'), ('experience', 'Experience Letter'), ('other', 'Other')], default='other', max_length=20, verbose_name='Document Type')), - ('description', models.CharField(blank=True, max_length=200, verbose_name='Description')), - ('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Uploaded By')), - ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='recruitment.person', verbose_name='Person')), - ], - options={ - 'verbose_name': 'Document', - 'verbose_name_plural': 'Documents', - 'ordering': ['-created_at'], - }, - ), migrations.AddField( model_name='application', name='person', @@ -553,8 +535,11 @@ class Migration(migrations.Migration): ('updated_at', models.DateTimeField(auto_now=True)), ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.application')), ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.jobposting')), + ('onsite_meeting', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='onsite_interview', to='recruitment.onsitemeeting')), + ('participants', models.ManyToManyField(blank=True, to='recruitment.participants')), ('schedule', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interviews', to='recruitment.interviewschedule')), - ('zoom_meeting', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting')), + ('system_users', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL)), + ('zoom_meeting', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting')), ], ), migrations.CreateModel( @@ -617,6 +602,27 @@ class Migration(migrations.Migration): 'indexes': [models.Index(fields=['unique_token'], name='recruitment_unique__f91e76_idx'), models.Index(fields=['expires_at'], name='recruitment_expires_954ed9_idx'), models.Index(fields=['is_active'], name='recruitment_is_acti_4b0804_idx')], }, ), + migrations.CreateModel( + name='Document', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), + ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), + ('object_id', models.PositiveIntegerField(verbose_name='Object ID')), + ('file', models.FileField(upload_to='documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File')), + ('document_type', models.CharField(choices=[('resume', 'Resume'), ('cover_letter', 'Cover Letter'), ('certificate', 'Certificate'), ('id_document', 'ID Document'), ('passport', 'Passport'), ('education', 'Education Document'), ('experience', 'Experience Letter'), ('other', 'Other')], default='other', max_length=20, verbose_name='Document Type')), + ('description', models.CharField(blank=True, max_length=200, verbose_name='Description')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Content Type')), + ('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Uploaded By')), + ], + options={ + 'verbose_name': 'Document', + 'verbose_name_plural': 'Documents', + 'ordering': ['-created_at'], + 'indexes': [models.Index(fields=['content_type', 'object_id', 'document_type', 'created_at'], name='recruitment_content_547650_idx')], + }, + ), migrations.CreateModel( name='FieldResponse', fields=[ @@ -707,10 +713,6 @@ class Migration(migrations.Migration): model_name='person', index=models.Index(fields=['created_at'], name='recruitment_created_33495a_idx'), ), - migrations.AddIndex( - model_name='document', - index=models.Index(fields=['person', 'document_type', 'created_at'], name='recruitment_person__0a6844_idx'), - ), migrations.AddIndex( model_name='application', index=models.Index(fields=['person', 'job'], name='recruitment_person__34355c_idx'), diff --git a/recruitment/migrations/0002_delete_candidate_and_more.py b/recruitment/migrations/0002_delete_candidate_and_more.py deleted file mode 100644 index 1d47a45..0000000 --- a/recruitment/migrations/0002_delete_candidate_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 5.2.6 on 2025-11-11 10:17 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0001_initial'), - ] - - operations = [ - migrations.DeleteModel( - name='Candidate', - ), - migrations.RenameField( - model_name='interviewschedule', - old_name='candidates', - new_name='applications', - ), - migrations.RemoveField( - model_name='application', - name='user', - ), - ] diff --git a/recruitment/migrations/0002_scheduledinterview_participants.py b/recruitment/migrations/0002_scheduledinterview_participants.py deleted file mode 100644 index 71c0a2c..0000000 --- a/recruitment/migrations/0002_scheduledinterview_participants.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-06 15:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='scheduledinterview', - name='participants', - field=models.ManyToManyField(blank=True, to='recruitment.participants'), - ), - ] diff --git a/recruitment/migrations/0003_convert_document_to_generic_fk.py b/recruitment/migrations/0003_convert_document_to_generic_fk.py deleted file mode 100644 index 2d3f90c..0000000 --- a/recruitment/migrations/0003_convert_document_to_generic_fk.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 5.2.6 on 2025-11-11 12:13 - -import django.db.models.deletion -import recruitment.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('recruitment', '0002_delete_candidate_and_more'), - ] - - operations = [ - migrations.RemoveIndex( - model_name='document', - name='recruitment_person__0a6844_idx', - ), - migrations.RemoveField( - model_name='document', - name='person', - ), - migrations.AddField( - model_name='document', - name='content_type', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Content Type'), - preserve_default=False, - ), - migrations.AddField( - model_name='document', - name='object_id', - field=models.PositiveIntegerField(default=1, verbose_name='Object ID'), - preserve_default=False, - ), - migrations.AlterField( - model_name='document', - name='file', - field=models.FileField(upload_to='documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File'), - ), - migrations.AddIndex( - model_name='document', - index=models.Index(fields=['content_type', 'object_id', 'document_type', 'created_at'], name='recruitment_content_547650_idx'), - ), - ] diff --git a/recruitment/migrations/0003_scheduledinterview_system_users.py b/recruitment/migrations/0003_scheduledinterview_system_users.py deleted file mode 100644 index e365758..0000000 --- a/recruitment/migrations/0003_scheduledinterview_system_users.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-06 15:37 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0002_scheduledinterview_participants'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='scheduledinterview', - name='system_users', - field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/recruitment/migrations/0004_person_agency.py b/recruitment/migrations/0004_person_agency.py deleted file mode 100644 index 24bd305..0000000 --- a/recruitment/migrations/0004_person_agency.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.6 on 2025-11-12 20:22 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0003_convert_document_to_generic_fk'), - ] - - operations = [ - migrations.AddField( - model_name='person', - name='agency', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency'), - ), - ] diff --git a/recruitment/migrations/0004_remove_jobposting_participants_and_more.py b/recruitment/migrations/0004_remove_jobposting_participants_and_more.py deleted file mode 100644 index 9368b3a..0000000 --- a/recruitment/migrations/0004_remove_jobposting_participants_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-06 15:44 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0003_scheduledinterview_system_users'), - ] - - operations = [ - migrations.RemoveField( - model_name='jobposting', - name='participants', - ), - migrations.RemoveField( - model_name='jobposting', - name='users', - ), - ] diff --git a/recruitment/migrations/0005_scheduledinterview_meeting_type.py b/recruitment/migrations/0005_scheduledinterview_meeting_type.py deleted file mode 100644 index fe94194..0000000 --- a/recruitment/migrations/0005_scheduledinterview_meeting_type.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 11:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0004_remove_jobposting_participants_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='scheduledinterview', - name='meeting_type', - field=models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type'), - ), - ] diff --git a/recruitment/migrations/0006_remove_scheduledinterview_meeting_type_and_more.py b/recruitment/migrations/0006_remove_scheduledinterview_meeting_type_and_more.py deleted file mode 100644 index 9270e59..0000000 --- a/recruitment/migrations/0006_remove_scheduledinterview_meeting_type_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 11:12 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0005_scheduledinterview_meeting_type'), - ] - - operations = [ - migrations.RemoveField( - model_name='scheduledinterview', - name='meeting_type', - ), - migrations.AddField( - model_name='interviewschedule', - name='meeting_type', - field=models.CharField(choices=[('Remote', 'Remote Interview'), ('Onsite', 'In-Person Interview')], default='Remote', max_length=10, verbose_name='Interview Meeting Type'), - ), - ] diff --git a/recruitment/migrations/0007_rename_meeting_type_interviewschedule_interview_type.py b/recruitment/migrations/0007_rename_meeting_type_interviewschedule_interview_type.py deleted file mode 100644 index 85e6f83..0000000 --- a/recruitment/migrations/0007_rename_meeting_type_interviewschedule_interview_type.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 11:30 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0006_remove_scheduledinterview_meeting_type_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='interviewschedule', - old_name='meeting_type', - new_name='interview_type', - ), - ] diff --git a/recruitment/migrations/0008_interviewschedule_location.py b/recruitment/migrations/0008_interviewschedule_location.py deleted file mode 100644 index 2800b75..0000000 --- a/recruitment/migrations/0008_interviewschedule_location.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 12:37 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0007_rename_meeting_type_interviewschedule_interview_type'), - ] - - operations = [ - migrations.AddField( - model_name='interviewschedule', - name='location', - field=models.CharField(blank=True, default='Remote', null=True), - ), - ] diff --git a/recruitment/migrations/0009_alter_zoommeeting_meeting_id.py b/recruitment/migrations/0009_alter_zoommeeting_meeting_id.py deleted file mode 100644 index 602917a..0000000 --- a/recruitment/migrations/0009_alter_zoommeeting_meeting_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 13:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0008_interviewschedule_location'), - ] - - operations = [ - migrations.AlterField( - model_name='zoommeeting', - name='meeting_id', - field=models.CharField(blank=True, db_index=True, max_length=20, null=True, unique=True, verbose_name='Meeting ID'), - ), - ] diff --git a/recruitment/migrations/0010_alter_zoommeeting_meeting_id.py b/recruitment/migrations/0010_alter_zoommeeting_meeting_id.py deleted file mode 100644 index d64f578..0000000 --- a/recruitment/migrations/0010_alter_zoommeeting_meeting_id.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 13:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0009_alter_zoommeeting_meeting_id'), - ] - - operations = [ - migrations.AlterField( - model_name='zoommeeting', - name='meeting_id', - field=models.CharField(db_index=True, default=1, max_length=20, unique=True, verbose_name='Meeting ID'), - preserve_default=False, - ), - ] diff --git a/recruitment/migrations/0011_alter_scheduledinterview_zoom_meeting.py b/recruitment/migrations/0011_alter_scheduledinterview_zoom_meeting.py deleted file mode 100644 index dba9c62..0000000 --- a/recruitment/migrations/0011_alter_scheduledinterview_zoom_meeting.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-09 13:50 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0010_alter_zoommeeting_meeting_id'), - ] - - operations = [ - migrations.AlterField( - model_name='scheduledinterview', - name='zoom_meeting', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.zoommeeting'), - ), - ] diff --git a/recruitment/migrations/0012_interviewschedule_interview_topic.py b/recruitment/migrations/0012_interviewschedule_interview_topic.py deleted file mode 100644 index fbf21b7..0000000 --- a/recruitment/migrations/0012_interviewschedule_interview_topic.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-10 09:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0011_alter_scheduledinterview_zoom_meeting'), - ] - - operations = [ - migrations.AddField( - model_name='interviewschedule', - name='interview_topic', - field=models.CharField(blank=True, null=True), - ), - ] diff --git a/recruitment/migrations/0013_onsitemeeting_and_more.py b/recruitment/migrations/0013_onsitemeeting_and_more.py deleted file mode 100644 index 4cb09d6..0000000 --- a/recruitment/migrations/0013_onsitemeeting_and_more.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-10 13:00 - -import django.db.models.deletion -import django_extensions.db.fields -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0012_interviewschedule_interview_topic'), - ] - - operations = [ - migrations.CreateModel( - name='OnsiteMeeting', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), - ('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')), - ('topic', models.CharField(max_length=255, verbose_name='Topic')), - ('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')), - ('duration', models.PositiveIntegerField(verbose_name='Duration')), - ('timezone', models.CharField(max_length=50, verbose_name='Timezone')), - ('location', models.CharField(blank=True, null=True)), - ], - options={ - 'abstract': False, - }, - ), - migrations.RemoveField( - model_name='interviewschedule', - name='interview_topic', - ), - migrations.RemoveField( - model_name='interviewschedule', - name='location', - ), - migrations.AddField( - model_name='scheduledinterview', - name='onsite_meeting', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interview', to='recruitment.onsitemeeting'), - ), - ] diff --git a/recruitment/migrations/0014_onsitemeeting_status.py b/recruitment/migrations/0014_onsitemeeting_status.py deleted file mode 100644 index 78270f1..0000000 --- a/recruitment/migrations/0014_onsitemeeting_status.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-10 13:20 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0013_onsitemeeting_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='onsitemeeting', - name='status', - field=models.CharField(blank=True, db_index=True, default='waiting', max_length=20, null=True, verbose_name='Status'), - ), - ] diff --git a/recruitment/migrations/0015_alter_scheduledinterview_onsite_meeting.py b/recruitment/migrations/0015_alter_scheduledinterview_onsite_meeting.py deleted file mode 100644 index 3127c6b..0000000 --- a/recruitment/migrations/0015_alter_scheduledinterview_onsite_meeting.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-10 13:55 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('recruitment', '0014_onsitemeeting_status'), - ] - - operations = [ - migrations.AlterField( - model_name='scheduledinterview', - name='onsite_meeting', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='onsite_interview', to='recruitment.onsitemeeting'), - ), - ] diff --git a/recruitment/migrations/__pycache__/0001_initial.cpython-313.pyc b/recruitment/migrations/__pycache__/0001_initial.cpython-313.pyc index 18266ec..e3b2eb3 100644 Binary files a/recruitment/migrations/__pycache__/0001_initial.cpython-313.pyc and b/recruitment/migrations/__pycache__/0001_initial.cpython-313.pyc differ diff --git a/test_agency_access_links.py b/test_agency_access_links.py deleted file mode 100644 index 354e883..0000000 --- a/test_agency_access_links.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -import os -import sys -import django - -# Add project root to Python path -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -# Set Django settings module -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') - -# Initialize Django -django.setup() - -def test_agency_access_links(): - """Test agency access link functionality""" - print("Testing agency access links...") - - # Test 1: Check if URLs exist - try: - from recruitment.urls import urlpatterns - print("✅ URL patterns loaded successfully") - - # Check if our new URLs are in patterns - url_patterns = [str(pattern.pattern) for pattern in urlpatterns] - - # Look for our specific URL patterns - deactivate_found = any('agency-access-links' in pattern and 'deactivate' in pattern for pattern in url_patterns) - reactivate_found = any('agency-access-links' in pattern and 'reactivate' in pattern for pattern in url_patterns) - - if deactivate_found: - print("✅ Found URL pattern for agency_access_link_deactivate") - else: - print("❌ Missing URL pattern for agency_access_link_deactivate") - - if reactivate_found: - print("✅ Found URL pattern for agency_access_link_reactivate") - else: - print("❌ Missing URL pattern for agency_access_link_reactivate") - - # Test 2: Check if views exist - try: - from recruitment.views import agency_access_link_deactivate, agency_access_link_reactivate - print("✅ View functions imported successfully") - - # Test that functions are callable - if callable(agency_access_link_deactivate): - print("✅ agency_access_link_deactivate is callable") - else: - print("❌ agency_access_link_deactivate is not callable") - - if callable(agency_access_link_reactivate): - print("✅ agency_access_link_reactivate is callable") - else: - print("❌ agency_access_link_reactivate is not callable") - - except ImportError as e: - print(f"❌ Import error: {e}") - - print("Agency access link functionality test completed!") - return True - except Exception as e: - print(f"❌ Test failed: {e}") - return False - -if __name__ == "__main__": - test_agency_access_links() diff --git a/test_agency_assignments.py b/test_agency_assignments.py deleted file mode 100644 index 586e93d..0000000 --- a/test_agency_assignments.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -""" -Test script to verify agency assignment functionality -""" -import os -import sys -import django - -# Setup Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from django.test import Client -from django.urls import reverse -from django.contrib.auth.models import User -from recruitment.models import HiringAgency, JobPosting, AgencyJobAssignment - -def test_agency_assignments(): - """Test agency assignment functionality""" - print("🧪 Testing Agency Assignment Functionality") - print("=" * 50) - - # Create test client - client = Client() - - # Test URLs - urls_to_test = [ - ('agency_list', '/recruitment/agencies/'), - ('agency_assignment_list', '/recruitment/agency-assignments/'), - ] - - print("\n📋 Testing URL Accessibility:") - for url_name, expected_path in urls_to_test: - try: - url = reverse(url_name) - print(f"✅ {url_name}: {url}") - except Exception as e: - print(f"❌ {url_name}: Error - {e}") - - print("\n🔍 Testing Views:") - - # Test agency list view (without authentication - should redirect) - try: - response = client.get(reverse('agency_list')) - if response.status_code == 302: # Redirect to login - print("✅ Agency list view redirects unauthenticated users (as expected)") - else: - print(f"⚠️ Agency list view status: {response.status_code}") - except Exception as e: - print(f"❌ Agency list view error: {e}") - - # Test agency assignment list view (without authentication - should redirect) - try: - response = client.get(reverse('agency_assignment_list')) - if response.status_code == 302: # Redirect to login - print("✅ Agency assignment list view redirects unauthenticated users (as expected)") - else: - print(f"⚠️ Agency assignment list view status: {response.status_code}") - except Exception as e: - print(f"❌ Agency assignment list view error: {e}") - - print("\n📊 Testing Database Models:") - - # Test if models exist and can be created - try: - # Check if we can query the models - agency_count = HiringAgency.objects.count() - job_count = JobPosting.objects.count() - assignment_count = AgencyJobAssignment.objects.count() - - print(f"✅ HiringAgency model: {agency_count} agencies in database") - print(f"✅ JobPosting model: {job_count} jobs in database") - print(f"✅ AgencyJobAssignment model: {assignment_count} assignments in database") - - except Exception as e: - print(f"❌ Database model error: {e}") - - print("\n🎯 Navigation Menu Test:") - print("✅ Agency Assignments link added to navigation menu") - print("✅ Navigation includes both 'Agencies' and 'Agency Assignments' links") - - print("\n📝 Summary:") - print("✅ Agency assignment functionality is fully implemented") - print("✅ All required views are present in views.py") - print("✅ URL patterns are configured in urls.py") - print("✅ Navigation menu has been updated") - print("✅ Templates are created and functional") - - print("\n🚀 Ready for use!") - print("Users can now:") - print(" - View agencies at /recruitment/agencies/") - print(" - Manage agency assignments at /recruitment/agency-assignments/") - print(" - Create, update, and delete assignments") - print(" - Generate access links for external agencies") - print(" - Send messages to agencies") - -if __name__ == '__main__': - test_agency_assignments() diff --git a/test_agency_crud.py b/test_agency_crud.py deleted file mode 100644 index e2f9da1..0000000 --- a/test_agency_crud.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python -""" -Test script to verify Agency CRUD functionality -""" -import os -import sys -import django - -# Add the project directory to the Python path -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -# Set up Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from django.test import Client -from django.contrib.auth.models import User -from recruitment.models import HiringAgency - -def test_agency_crud(): - """Test Agency CRUD operations""" - print("🧪 Testing Agency CRUD Functionality") - print("=" * 50) - - # Create a test user - user, created = User.objects.get_or_create( - username='testuser', - defaults={'email': 'test@example.com', 'is_staff': True, 'is_superuser': True} - ) - if created: - user.set_password('testpass123') - user.save() - print("✅ Created test user") - else: - print("ℹ️ Using existing test user") - - # Create test client - client = Client() - - # Login the user - client.login(username='testuser', password='testpass123') - print("✅ Logged in test user") - - # Test 1: Agency List View - print("\n1. Testing Agency List View...") - response = client.get('/recruitment/agencies/') - if response.status_code == 200: - print("✅ Agency list view works") - else: - print(f"❌ Agency list view failed: {response.status_code}") - return False - - # Test 2: Agency Create View (GET) - print("\n2. Testing Agency Create View (GET)...") - response = client.get('/recruitment/agencies/create/') - if response.status_code == 200: - print("✅ Agency create view works") - else: - print(f"❌ Agency create view failed: {response.status_code}") - return False - - # Test 3: Agency Create (POST) - print("\n3. Testing Agency Create (POST)...") - agency_data = { - 'name': 'Test Agency', - 'contact_person': 'John Doe', - 'email': 'test@agency.com', - 'phone': '+1234567890', - 'country': 'SA', - 'city': 'Riyadh', - 'address': 'Test Address', - 'website': 'https://testagency.com', - 'description': 'Test agency description' - } - - response = client.post('/recruitment/agencies/create/', agency_data) - if response.status_code == 302: # Redirect after successful creation - print("✅ Agency creation works") - - # Get the created agency - agency = HiringAgency.objects.filter(name='Test Agency').first() - if agency: - print(f"✅ Agency created with ID: {agency.id}") - - # Test 4: Agency Detail View - print("\n4. Testing Agency Detail View...") - response = client.get(f'/recruitment/agencies/{agency.slug}/') - if response.status_code == 200: - print("✅ Agency detail view works") - else: - print(f"❌ Agency detail view failed: {response.status_code}") - return False - - # Test 5: Agency Update View (GET) - print("\n5. Testing Agency Update View (GET)...") - response = client.get(f'/recruitment/agencies/{agency.slug}/update/') - if response.status_code == 200: - print("✅ Agency update view works") - else: - print(f"❌ Agency update view failed: {response.status_code}") - return False - - # Test 6: Agency Update (POST) - print("\n6. Testing Agency Update (POST)...") - update_data = agency_data.copy() - update_data['name'] = 'Updated Test Agency' - - response = client.post(f'/recruitment/agencies/{agency.slug}/update/', update_data) - if response.status_code == 302: - print("✅ Agency update works") - - # Verify the update - agency.refresh_from_db() - if agency.name == 'Updated Test Agency': - print("✅ Agency data updated correctly") - else: - print("❌ Agency data not updated correctly") - return False - else: - print(f"❌ Agency update failed: {response.status_code}") - return False - - # Test 7: Agency Delete View (GET) - print("\n7. Testing Agency Delete View (GET)...") - response = client.get(f'/recruitment/agencies/{agency.slug}/delete/') - if response.status_code == 200: - print("✅ Agency delete view works") - else: - print(f"❌ Agency delete view failed: {response.status_code}") - return False - - # Test 8: Agency Delete (POST) - print("\n8. Testing Agency Delete (POST)...") - delete_data = { - 'confirm_name': 'Updated Test Agency', - 'confirm_delete': 'on' - } - - response = client.post(f'/recruitment/agencies/{agency.slug}/delete/', delete_data) - if response.status_code == 302: - print("✅ Agency deletion works") - - # Verify deletion - if not HiringAgency.objects.filter(name='Updated Test Agency').exists(): - print("✅ Agency deleted successfully") - else: - print("❌ Agency not deleted") - return False - else: - print(f"❌ Agency deletion failed: {response.status_code}") - return False - - else: - print("❌ Agency not found after creation") - return False - else: - print(f"❌ Agency creation failed: {response.status_code}") - print(f"Response content: {response.content.decode()}") - return False - - # Test 9: URL patterns - print("\n9. Testing URL patterns...") - try: - from django.urls import reverse - print(f"✅ Agency list URL: {reverse('agency_list')}") - print(f"✅ Agency create URL: {reverse('agency_create')}") - print("✅ All URL patterns resolved correctly") - except Exception as e: - print(f"❌ URL pattern error: {e}") - return False - - # Test 10: Model functionality - print("\n10. Testing Model functionality...") - try: - # Test model creation - test_agency = HiringAgency.objects.create( - name='Model Test Agency', - contact_person='Jane Smith', - email='model@test.com', - phone='+9876543210', - country='SA' - ) - print(f"✅ Model creation works: {test_agency.name}") - print(f"✅ Slug generation works: {test_agency.slug}") - print(f"✅ String representation works: {str(test_agency)}") - - # Test model methods - print(f"✅ Country display: {test_agency.get_country_display()}") - - # Clean up - test_agency.delete() - print("✅ Model deletion works") - - except Exception as e: - print(f"❌ Model functionality error: {e}") - return False - - print("\n" + "=" * 50) - print("🎉 All Agency CRUD tests passed!") - return True - -if __name__ == '__main__': - success = test_agency_crud() - sys.exit(0 if success else 1) diff --git a/test_agency_isolation.py b/test_agency_isolation.py deleted file mode 100644 index 3ffa2bc..0000000 --- a/test_agency_isolation.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python -""" -Test script to verify agency user isolation and all fixes are working properly. -This tests: -1. Agency login functionality (AttributeError fix) -2. Agency portal template isolation (agency_base.html usage) -3. Agency user access restrictions -4. JavaScript fixes in submit candidate form -""" - -import os -import sys -import django -from django.test import TestCase, Client -from django.urls import reverse -from django.contrib.auth.models import User -from unittest.mock import patch, MagicMock - -# Setup Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from recruitment.models import Agency, AgencyJobAssignment, AgencyAccessLink, Candidate, Job - - -class AgencyIsolationTest(TestCase): - """Test agency user isolation and functionality""" - - def setUp(self): - """Set up test data""" - # Create internal staff user - self.staff_user = User.objects.create_user( - username='staff_user', - email='staff@example.com', - password='testpass123', - is_staff=True - ) - - # Create agency user - self.agency_user = User.objects.create_user( - username='agency_user', - email='agency@example.com', - password='testpass123', - is_staff=False - ) - - # Create agency - self.agency = Agency.objects.create( - name='Test Agency', - contact_email='agency@example.com', - contact_phone='+1234567890', - address='Test Address', - is_active=True - ) - - # Create job - self.job = Job.objects.create( - title='Test Job', - department='IT', - description='Test job description', - status='active' - ) - - # Create agency assignment - self.assignment = AgencyJobAssignment.objects.create( - agency=self.agency, - job=self.job, - max_candidates=10, - deadline_date='2024-12-31', - status='active' - ) - - # Create access link - self.access_link = AgencyAccessLink.objects.create( - assignment=self.assignment, - unique_token='test-token-123', - access_password='testpass123', - expires_at='2024-12-31' - ) - - # Create test candidate - self.candidate = Candidate.objects.create( - first_name='Test', - last_name='Candidate', - email='candidate@example.com', - phone='+1234567890', - job=self.job, - source='agency', - hiring_agency=self.agency - ) - - def test_agency_login_form_attribute_error_fix(self): - """Test that AgencyLoginForm handles missing validated_access_link attribute""" - from recruitment.forms import AgencyLoginForm - - # Test form with valid data - form_data = { - 'access_token': 'test-token-123', - 'password': 'testpass123' - } - - form = AgencyLoginForm(data=form_data) - - # This should not raise AttributeError anymore - try: - is_valid = form.is_valid() - print(f"✓ AgencyLoginForm validation works: {is_valid}") - except AttributeError as e: - if 'validated_access_link' in str(e): - self.fail("AttributeError 'validated_access_link' not fixed!") - else: - raise - - def test_agency_portal_templates_use_agency_base(self): - """Test that agency portal templates use agency_base.html""" - agency_portal_templates = [ - 'recruitment/agency_portal_login.html', - 'recruitment/agency_portal_dashboard.html', - 'recruitment/agency_portal_submit_candidate.html', - 'recruitment/agency_portal_messages.html', - 'recruitment/agency_access_link_detail.html' - ] - - for template_name in agency_portal_templates: - template_path = f'templates/{template_name}' - if os.path.exists(template_path): - with open(template_path, 'r') as f: - content = f.read() - self.assertIn("{% extends 'agency_base.html' %}", content, - f"{template_name} should use agency_base.html") - print(f"✓ {template_name} uses agency_base.html") - else: - print(f"⚠ Template {template_name} not found") - - def test_agency_base_template_isolation(self): - """Test that agency_base.html properly isolates agency users""" - agency_base_path = 'templates/agency_base.html' - - if os.path.exists(agency_base_path): - with open(agency_base_path, 'r') as f: - content = f.read() - - # Check that it extends base.html - self.assertIn("{% extends 'base.html' %}", content) - - # Check that it has agency-specific navigation - self.assertIn('agency_portal_dashboard', content) - self.assertIn('agency_portal_logout', content) - - # Check that it doesn't include admin navigation - self.assertNotIn('admin:', content) - - print("✓ agency_base.html properly configured") - else: - self.fail("agency_base.html not found") - - def test_agency_login_view(self): - """Test agency login functionality""" - client = Client() - - # Test GET request - response = client.get(reverse('agency_portal_login')) - self.assertEqual(response.status_code, 200) - print("✓ Agency login page loads") - - # Test POST with valid credentials - response = client.post(reverse('agency_portal_login'), { - 'access_token': 'test-token-123', - 'password': 'testpass123' - }) - - # Should redirect or show success (depending on implementation) - self.assertIn(response.status_code, [200, 302]) - print("✓ Agency login POST request handled") - - def test_agency_user_access_restriction(self): - """Test that agency users can't access internal pages""" - client = Client() - - # Log in as agency user - client.login(username='agency_user', password='testpass123') - - # Try to access internal pages (should be restricted) - internal_urls = [ - '/admin/', - reverse('agency_list'), - reverse('candidate_list'), - ] - - for url in internal_urls: - try: - response = client.get(url) - # Agency users should get redirected or forbidden - self.assertIn(response.status_code, [302, 403, 404]) - print(f"✓ Agency user properly restricted from {url}") - except: - print(f"⚠ Could not test access to {url}") - - def test_javascript_fixes_in_submit_candidate(self): - """Test that JavaScript fixes are in place in submit candidate template""" - template_path = 'templates/recruitment/agency_portal_submit_candidate.html' - - if os.path.exists(template_path): - with open(template_path, 'r') as f: - content = f.read() - - # Check for safe element access patterns - self.assertIn('getElementValue', content) - self.assertIn('if (element)', content) - - # Check for error handling - self.assertIn('console.error', content) - - print("✓ JavaScript fixes present in submit candidate template") - else: - self.fail("agency_portal_submit_candidate.html not found") - - def test_agency_portal_navigation(self): - """Test agency portal navigation links""" - agency_portal_urls = [ - 'agency_portal_dashboard', - 'agency_portal_login', - 'agency_portal_logout', - ] - - for url_name in agency_portal_urls: - try: - url = reverse(url_name) - print(f"✓ Agency portal URL {url_name} resolves: {url}") - except: - print(f"⚠ Agency portal URL {url_name} not found") - - -def run_tests(): - """Run all tests""" - print("=" * 60) - print("AGENCY ISOLATION AND FIXES TEST") - print("=" * 60) - - test_case = AgencyIsolationTest() - test_case.setUp() - - tests = [ - test_case.test_agency_login_form_attribute_error_fix, - test_case.test_agency_portal_templates_use_agency_base, - test_case.test_agency_base_template_isolation, - test_case.test_agency_login_view, - test_case.test_agency_user_access_restriction, - test_case.test_javascript_fixes_in_submit_candidate, - test_case.test_agency_portal_navigation, - ] - - passed = 0 - failed = 0 - - for test in tests: - try: - test() - passed += 1 - except Exception as e: - print(f"✗ {test.__name__} failed: {e}") - failed += 1 - - print("=" * 60) - print(f"TEST RESULTS: {passed} passed, {failed} failed") - print("=" * 60) - - if failed == 0: - print("🎉 All tests passed! Agency isolation is working properly.") - else: - print("⚠️ Some tests failed. Please review the issues above.") - - return failed == 0 - - -if __name__ == '__main__': - success = run_tests() - sys.exit(0 if success else 1) diff --git a/test_async_email.py b/test_async_email.py deleted file mode 100644 index a90c1d0..0000000 --- a/test_async_email.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -""" -Test script for async email functionality -""" - -import os -import sys -import django - -# Setup Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from django.contrib.auth.models import User -from recruitment.email_service import send_bulk_email -from recruitment.models import JobPosting, Candidate - -def test_async_email(): - """Test async email sending functionality""" - - print("🧪 Testing Async Email Functionality") - print("=" * 50) - - try: - # Get a test user - test_user = User.objects.first() - if not test_user: - print("❌ No users found in database. Please create a user first.") - return - - # Get a test job and candidate - test_job = JobPosting.objects.first() - test_candidate = Candidate.objects.first() - - if not test_job or not test_candidate: - print("❌ No test job or candidate found. Please create some test data first.") - return - - print(f"📧 Test User: {test_user.email}") - print(f"💼 Test Job: {test_job.title}") - print(f"👤 Test Candidate: {test_candidate.name}") - - # Test synchronous email sending - print("\n1. Testing Synchronous Email Sending...") - try: - sync_result = send_bulk_email( - subject="Test Synchronous Email", - message="This is a test synchronous email from the ATS system.", - recipient_list=[test_user.email], - async_task=False - ) - print(f" ✅ Sync result: {sync_result}") - except Exception as e: - print(f" ❌ Sync error: {e}") - - # Test asynchronous email sending - print("\n2. Testing Asynchronous Email Sending...") - try: - async_result = send_bulk_email( - subject="Test Asynchronous Email", - message="This is a test asynchronous email from the ATS system.", - recipient_list=[test_user.email], - async_task=True - ) - print(f" ✅ Async result: {async_result}") - except Exception as e: - print(f" ❌ Async error: {e}") - - print("\n3. Testing Email Service Status...") - - # Check Django Q configuration - try: - import django_q - from django_q.models import Task - pending_tasks = Task.objects.count() - print(f" 📊 Django Q Status: Installed, {pending_tasks} tasks in queue") - except ImportError: - print(" ⚠️ Django Q not installed") - except Exception as e: - print(f" 📊 Django Q Status: Installed but error checking status: {e}") - - # Check email backend configuration - from django.conf import settings - email_backend = getattr(settings, 'EMAIL_BACKEND', 'not configured') - print(f" 📧 Email Backend: {email_backend}") - - email_host = getattr(settings, 'EMAIL_HOST', 'not configured') - print(f" 🌐 Email Host: {email_host}") - - email_port = getattr(settings, 'EMAIL_PORT', 'not configured') - print(f" 🔌 Email Port: {email_port}") - - print("\n✅ Async email functionality test completed!") - print("💡 If emails are not being received, check:") - print(" - Email server configuration in settings.py") - print(" - Django Q cluster status (python manage.py qmonitor)") - print(" - Email logs and spam folders") - - except Exception as e: - print(f"❌ Test failed with error: {e}") - import traceback - traceback.print_exc() - -if __name__ == "__main__": - test_async_email() diff --git a/test_csv_export.py b/test_csv_export.py deleted file mode 100644 index 25ac28d..0000000 --- a/test_csv_export.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -""" -Test script to verify CSV export functionality with updated JSON structure -""" -import os -import sys -import django - -# Setup Django environment -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from recruitment.models import Candidate, JobPosting -from recruitment.views_frontend import export_candidates_csv -from django.test import RequestFactory -from django.contrib.auth.models import User - -def test_csv_export(): - """Test the CSV export function with sample data""" - - print("🧪 Testing CSV Export Functionality") - print("=" * 50) - - # Create a test request factory - factory = RequestFactory() - - # Get or create a test user - user, created = User.objects.get_or_create( - username='testuser', - defaults={'email': 'test@example.com', 'is_staff': True} - ) - - # Get a sample job - job = JobPosting.objects.first() - if not job: - print("❌ No jobs found in database. Please create a job first.") - return False - - print(f"📋 Using job: {job.title}") - - # Test different stages - stages = ['screening', 'exam', 'interview', 'offer', 'hired'] - - for stage in stages: - print(f"\n🔍 Testing stage: {stage}") - - # Create a mock request - request = factory.get(f'/export/{job.slug}/{stage}/') - request.user = user - request.GET = {'search': ''} - - try: - # Call the export function - response = export_candidates_csv(request, job.slug, stage) - - # Check if response is successful - if response.status_code == 200: - print(f"✅ {stage} export successful") - - # Read and analyze the CSV content - content = response.content.decode('utf-8-sig') - lines = content.split('\n') - - if len(lines) > 1: - headers = lines[0].split(',') - print(f"📊 Headers: {len(headers)} columns") - print(f"📊 Data rows: {len(lines) - 1}") - - # Check for AI score column - if 'Match Score' in headers: - print("✅ Match Score column found") - else: - print("⚠️ Match Score column not found") - - # Check for other AI columns - ai_columns = ['Years Experience', 'Screening Rating', 'Professional Category', 'Top 3 Skills'] - found_ai_columns = [col for col in ai_columns if col in headers] - print(f"🤖 AI columns found: {found_ai_columns}") - - else: - print("⚠️ No data rows found") - - else: - print(f"❌ {stage} export failed with status: {response.status_code}") - - except Exception as e: - print(f"❌ {stage} export error: {str(e)}") - import traceback - traceback.print_exc() - - # Test with actual candidate data - print(f"\n🔍 Testing with actual candidate data") - candidates = Candidate.objects.filter(job=job) - print(f"📊 Total candidates for job: {candidates.count()}") - - if candidates.exists(): - # Test AI data extraction for first candidate - candidate = candidates.first() - print(f"\n🧪 Testing AI data extraction for: {candidate.name}") - - try: - # Test the model properties - print(f"📊 Match Score: {candidate.match_score}") - print(f"📊 Years Experience: {candidate.years_of_experience}") - print(f"📊 Screening Rating: {candidate.screening_stage_rating}") - print(f"📊 Professional Category: {candidate.professional_category}") - print(f"📊 Top 3 Skills: {candidate.top_3_keywords}") - print(f"📊 Strengths: {candidate.strengths}") - print(f"📊 Weaknesses: {candidate.weaknesses}") - - # Test AI analysis data structure - if candidate.ai_analysis_data: - print(f"📊 AI Analysis Data keys: {list(candidate.ai_analysis_data.keys())}") - if 'analysis_data' in candidate.ai_analysis_data: - analysis_keys = list(candidate.ai_analysis_data['analysis_data'].keys()) - print(f"📊 Analysis Data keys: {analysis_keys}") - else: - print("⚠️ 'analysis_data' key not found in ai_analysis_data") - else: - print("⚠️ No AI analysis data found") - - except Exception as e: - print(f"❌ Error extracting AI data: {str(e)}") - import traceback - traceback.print_exc() - - print("\n🎉 CSV Export Test Complete!") - return True - -if __name__ == '__main__': - test_csv_export() diff --git a/test_email_attachments.py b/test_email_attachments.py deleted file mode 100644 index 040d695..0000000 --- a/test_email_attachments.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -""" -Test script for email attachment functionality -""" - -import os -import django -from django.conf import settings -from django.test import TestCase, Client -from django.core.files.uploadedfile import SimpleUploadedFile -from django.core.files.base import ContentFile -import io -from unittest.mock import Mock -from recruitment.email_service import send_bulk_email -from recruitment.forms import CandidateEmailForm -from recruitment.models import JobPosting, Candidate -from django.test import RequestFactory -from django.contrib.auth.models import User - -# Configure Django settings -if not settings.configured: - settings.configure( - DEBUG=True, - DATABASES={ - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } - }, - USE_TZ=True, - SECRET_KEY='test-secret-key', - INSTALLED_APPS=[ - 'django.contrib.contenttypes', - 'django.contrib.auth', - 'django.contrib.sessions', - 'recruitment', - ], - EMAIL_BACKEND='django.core.mail.backends.console.EmailBackend', - ) - -# Setup test database -from django.db import connection -from django.core.management import execute_from_command_line - -def setup_test_data(): - """Create test data for email attachment testing""" - # Create test user - user = User.objects.create_user( - username='testuser', - email='test@example.com', - first_name='Test', - last_name='User' - ) - - # Create test job - job = JobPosting.objects.create( - title='Test Job Position', - description='This is a test job for email attachment testing.', - status='ACTIVE', - internal_job_id='TEST-001' - ) - - # Create test candidate - candidate = Candidate.objects.create( - first_name='John', - last_name='Doe', - email='john.doe@example.com', - phone='+1234567890', - address='123 Test Street', - job=job, - stage='Interview' - ) - - return user, job, candidate - -def test_email_service_with_attachments(): - """Test the email service directly with attachments""" - print("Testing email service with attachments...") - - # Create test files - test_files = [] - - # Test 1: Simple text file - text_content = "This is a test attachment content." - text_file = ContentFile( - text_content.encode('utf-8'), - name='test_document.txt' - ) - test_files.append(('test_document.txt', text_file, 'text/plain')) - - # Test 2: PDF content (simulated) - pdf_content = b'%PDF-1.4\n1 0 obj\n<<\n/Length 100\n>>stream\nxref\nstartxref\n1234\n5678\n/ModDate(D:20250101)\n' - pdf_file = ContentFile( - pdf_content, - name='test_document.pdf' - ) - test_files.append(('test_document.pdf', pdf_file, 'application/pdf')) - - # Test 3: Image file (simulated) - image_content = b'\x89PNG\r\n\x8a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 diff --git a/test_email_attachments_clean.py b/test_email_attachments_clean.py deleted file mode 100644 index 15c50ea..0000000 --- a/test_email_attachments_clean.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python -""" -Clean test script for email attachment functionality -""" - -import os -import sys -import django -from django.conf import settings - -# Configure Django settings BEFORE importing any Django modules -if not settings.configured: - settings.configure( - DEBUG=True, - DATABASES={ - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } - }, - USE_TZ=True, - SECRET_KEY='test-secret-key', - INSTALLED_APPS=[ - 'django.contrib.contenttypes', - 'django.contrib.auth', - 'django.contrib.sessions', - 'recruitment', - ], - EMAIL_BACKEND='django.core.mail.backends.console.EmailBackend', - MEDIA_ROOT='/tmp/test_media', - FILE_UPLOAD_TEMP_DIR='/tmp/test_uploads', - ) - -# Setup Django -django.setup() - -# Now import Django modules -from django.test import TestCase, Client -from django.core.files.uploadedfile import SimpleUploadedFile -from django.core.files.base import ContentFile -import io -from unittest.mock import Mock -from recruitment.email_service import send_bulk_email -from recruitment.forms import CandidateEmailForm -from recruitment.models import JobPosting, Candidate -from django.test import RequestFactory -from django.contrib.auth.models import User - -# Setup test database -from django.db import connection -from django.core.management import execute_from_command_line - -def setup_test_data(): - """Create test data for email attachment testing""" - # Create test user - user = User.objects.create_user( - username='testuser', - email='test@example.com', - first_name='Test', - last_name='User' - ) - - # Create test job - job = JobPosting.objects.create( - title='Test Job Position', - description='This is a test job for email attachment testing.', - status='ACTIVE', - internal_job_id='TEST-001' - ) - - # Create test candidate - candidate = Candidate.objects.create( - first_name='John', - last_name='Doe', - email='john.doe@example.com', - phone='+1234567890', - address='123 Test Street', - job=job, - stage='Interview' - ) - - return user, job, candidate - -def test_email_service_with_attachments(): - """Test the email service directly with attachments""" - print("Testing email service with attachments...") - - # Create test files - test_files = [] - - # Test 1: Simple text file - text_content = "This is a test attachment content." - text_file = ContentFile( - text_content.encode('utf-8'), - name='test_document.txt' - ) - test_files.append(('test_document.txt', text_file, 'text/plain')) - - # Test 2: PDF content (simulated) - pdf_content = b'%PDF-1.4\n1 0 obj\n<<\n/Length 100\n>>stream\nxref\nstartxref\n1234\n5678\n/ModDate(D:20250101)\n' - pdf_file = ContentFile( - pdf_content, - name='test_document.pdf' - ) - test_files.append(('test_document.pdf', pdf_file, 'application/pdf')) - - # Test 3: Image file (simulated PNG header) - image_content = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01' - image_file = ContentFile( - image_content, - name='test_image.png' - ) - test_files.append(('test_image.png', image_file, 'image/png')) - - try: - # Test email service with attachments - result = send_bulk_email( - subject='Test Email with Attachments', - body='This is a test email with attachments.', - from_email='test@example.com', - recipient_list=['recipient@example.com'], - attachments=test_files - ) - - print(f"Email service result: {result}") - print("✓ Email service with attachments test passed") - return True - - except Exception as e: - print(f"✗ Email service test failed: {e}") - return False - -def test_candidate_email_form_with_attachments(): - """Test the CandidateEmailForm with attachments""" - print("\nTesting CandidateEmailForm with attachments...") - - user, job, candidate = setup_test_data() - - # Create test files for form - text_file = SimpleUploadedFile( - "test.txt", - b"This is test content for form attachment" - ) - - pdf_file = SimpleUploadedFile( - "test.pdf", - b"%PDF-1.4 test content" - ) - - form_data = { - 'subject': 'Test Subject', - 'body': 'Test body content', - 'from_email': 'test@example.com', - 'recipient_list': 'recipient@example.com', - } - - files_data = { - 'attachments': [text_file, pdf_file] - } - - try: - form = CandidateEmailForm(data=form_data, files=files_data) - - if form.is_valid(): - print("✓ Form validation passed") - print(f"Form cleaned data: {form.cleaned_data}") - - # Test form processing - try: - result = form.save() - print(f"✓ Form save result: {result}") - return True - except Exception as e: - print(f"✗ Form save failed: {e}") - return False - else: - print(f"✗ Form validation failed: {form.errors}") - return False - - except Exception as e: - print(f"✗ Form test failed: {e}") - return False - -def test_email_view_with_attachments(): - """Test the email view with attachments""" - print("\nTesting email view with attachments...") - - user, job, candidate = setup_test_data() - factory = RequestFactory() - - # Create a mock request with files - text_file = SimpleUploadedFile( - "test.txt", - b"This is test content for view attachment" - ) - - request = factory.post( - '/recruitment/send-candidate-email/', - data={ - 'subject': 'Test Subject', - 'body': 'Test body content', - 'from_email': 'test@example.com', - 'recipient_list': 'recipient@example.com', - }, - format='multipart' - ) - request.FILES['attachments'] = [text_file] - request.user = user - - try: - # Import and test the view - from recruitment.views import send_candidate_email - - response = send_candidate_email(request) - print(f"View response status: {response.status_code}") - - if response.status_code == 200: - print("✓ Email view test passed") - return True - else: - print(f"✗ Email view test failed with status: {response.status_code}") - return False - - except Exception as e: - print(f"✗ Email view test failed: {e}") - return False - -def main(): - """Run all email attachment tests""" - print("=" * 60) - print("EMAIL ATTACHMENT FUNCTIONALITY TESTS") - print("=" * 60) - - # Initialize Django - django.setup() - - # Create tables - from django.core.management import execute_from_command_line - execute_from_command_line(['manage.py', 'migrate', '--run-syncdb']) - - results = [] - - # Run tests - results.append(test_email_service_with_attachments()) - results.append(test_candidate_email_form_with_attachments()) - results.append(test_email_view_with_attachments()) - - # Summary - print("\n" + "=" * 60) - print("TEST SUMMARY") - print("=" * 60) - - passed = sum(results) - total = len(results) - - print(f"Tests passed: {passed}/{total}") - - if passed == total: - print("🎉 All email attachment tests passed!") - return True - else: - print("❌ Some email attachment tests failed!") - return False - -if __name__ == '__main__': - success = main() - exit(0 if success else 1) diff --git a/test_email_composition.py b/test_email_composition.py deleted file mode 100644 index 6e540b6..0000000 --- a/test_email_composition.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python3 -""" -Test script to verify email composition functionality -""" - -import os -import sys -import django - -# Setup Django environment -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'NorahUniversity.settings') -django.setup() - -from django.test import TestCase, Client -from django.urls import reverse -from django.contrib.auth.models import User -from django.utils import timezone -from recruitment.models import JobPosting, Candidate -from unittest.mock import patch, MagicMock - -def test_email_composition_view(): - """Test the email composition view""" - print("Testing email composition view...") - - # Create test user (delete if exists) - User.objects.filter(username='testuser').delete() - user = User.objects.create_user( - username='testuser', - email='test@example.com', - password='testpass123' - ) - - # Create test job - job = JobPosting.objects.create( - title='Test Job', - internal_job_id='TEST001', - description='Test job description', - status='active', - application_deadline=timezone.now() + timezone.timedelta(days=30) - ) - - # Add user to job participants so they appear in recipient choices - job.users.add(user) - - # Create test candidate - candidate = Candidate.objects.create( - first_name='Test Candidate', - last_name='', - email='candidate@example.com', - phone='1234567890', - job=job - ) - - # Create client and login - client = Client() - client.login(username='testuser', password='testpass123') - - # Test GET request to email composition view - url = reverse('compose_candidate_email', kwargs={ - 'job_slug': job.slug, - 'candidate_slug': candidate.slug - }) - - try: - response = client.get(url) - print(f"✓ GET request successful: {response.status_code}") - - if response.status_code == 200: - print("✓ Email composition form rendered successfully") - - # Check if form contains expected fields - content = response.content.decode('utf-8') - if 'subject' in content.lower(): - print("✓ Subject field found in form") - if 'message' in content.lower(): - print("✓ Message field found in form") - if 'recipients' in content.lower(): - print("✓ Recipients field found in form") - - else: - print(f"✗ Unexpected status code: {response.status_code}") - - except Exception as e: - print(f"✗ Error testing GET request: {e}") - - # Test POST request with mock email sending - post_data = { - 'subject': 'Test Subject', - 'message': 'Test message content', - 'recipients': ['candidate@example.com'], - 'include_candidate_info': True, - 'include_meeting_details': False - } - - with patch('django.core.mail.send_mass_mail') as mock_send_mail: - mock_send_mail.return_value = 1 - - try: - response = client.post(url, data=post_data) - print(f"✓ POST request successful: {response.status_code}") - - if response.status_code == 200: - # Check if JSON response is correct - try: - json_data = response.json() - if json_data.get('success'): - print("✓ Email sent successfully") - print(f"✓ Success message: {json_data.get('message')}") - else: - print(f"✗ Email send failed: {json_data.get('error')}") - except: - print("✗ Invalid JSON response") - else: - print(f"✗ Unexpected status code: {response.status_code}") - - except Exception as e: - print(f"✗ Error testing POST request: {e}") - - # Clean up - user.delete() - job.delete() - candidate.delete() - - print("Email composition test completed!") - -def test_email_form(): - """Test the CandidateEmailForm""" - print("\nTesting CandidateEmailForm...") - - from recruitment.forms import CandidateEmailForm - - # Create test user for form (delete if exists) - User.objects.filter(username='formuser').delete() - form_user = User.objects.create_user( - username='formuser', - email='form@example.com', - password='formpass123' - ) - - # Create test job and candidate for form - job = JobPosting.objects.create( - title='Test Job Form', - internal_job_id='TEST002', - description='Test job description for form', - status='active', - application_deadline=timezone.now() + timezone.timedelta(days=30) - ) - - # Add user to job participants so they appear in recipient choices - job.users.add(form_user) - - candidate = Candidate.objects.create( - first_name='Test Candidate', - last_name='Form', - email='candidate_form@example.com', - phone='1234567890', - job=job - ) - - try: - # Test valid form data - get available choices from form - form = CandidateEmailForm(job, candidate) - available_choices = [choice[0] for choice in form.fields['recipients'].choices] - - # Use first available choice for testing - test_recipient = available_choices[0] if available_choices else None - - if test_recipient: - form = CandidateEmailForm(job, candidate, data={ - 'subject': 'Test Subject', - 'message': 'Test message content', - 'recipients': [test_recipient], - 'include_candidate_info': True, - 'include_meeting_details': False - }) - - if form.is_valid(): - print("✓ Form validation passed") - print(f"✓ Cleaned recipients: {form.cleaned_data['recipients']}") - else: - print(f"✗ Form validation failed: {form.errors}") - else: - print("✗ No recipient choices available for testing") - except Exception as e: - print(f"✗ Error testing form: {e}") - - try: - # Test invalid form data (empty subject) - form = CandidateEmailForm(job, candidate, data={ - 'subject': '', - 'message': 'Test message content', - 'recipients': [], - 'include_candidate_info': True, - 'include_meeting_details': False - }) - - if not form.is_valid(): - print("✓ Form correctly rejected empty subject") - if 'subject' in form.errors: - print("✓ Subject field has validation error") - else: - print("✗ Form should have failed validation") - except Exception as e: - print(f"✗ Error testing invalid form: {e}") - - # Clean up - job.delete() - candidate.delete() - -if __name__ == '__main__': - print("Running Email Composition Tests") - print("=" * 50) - - test_email_form() - test_email_composition_view() - - print("\n" + "=" * 50) - print("All tests completed!") diff --git a/test_email_form_js.html b/test_email_form_js.html deleted file mode 100644 index edc579f..0000000 --- a/test_email_form_js.html +++ /dev/null @@ -1,507 +0,0 @@ - - -
- - -Dear John Doe,
-Thank you for your interest in the position. We are pleased to invite you to a virtual interview. Please find the details below.
- -Please click the button above to join the meeting at the scheduled time.
- - -No notifications yet...
-python test_sse_notifications.py