Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00051.parquet:24771

b10c977ffe059fddd585cfcf
turn 4/6gpt-4o-2024-08-06RussianBelarus268 words
degenerate_repetitionAbsentFinal dense release
USER
Как бороться с синдромом навязчивых грёз, если это переросло в зависимость?
ASSISTANT
Синдром навязчивых грёз, или избыточное фантазирование, может существенно влиять на повседневную жизнь и эмоциональное состояние. Если это состояние переросло в зависимость, необходимо предпринять шаги для улучшения ситуации. Вот несколько рекомендаций, которые могут помочь:

1. **Осознание и принятие**: Признайте, что у вас есть проблема, и это первый шаг к её решению. Осознание того, что фантазирование стало чрезмерным и мешает вашей жизни, важно для процесса изменений.

2. **Самонаблюдение**: Ведите дневник, чтобы отслеживать, когда и почему вы начинаете фантазировать. Анализируя триггеры и ситуации, можно понять корни проблемы и начать их избегать.

3. **Установление границ**: Определите конкретное время для мечтаний в течение дня. Например, выделите 15-20 минут, когда вы можете предаваться этому занятию, а потом вернитесь к реальной жизни.

4. **Практики осознанности**: Занятия йогой, медитация и техники осознанности помогут укрепить связь с настоящим моментом и уменьшить время, проводимое в фантазиях.

5. **Замена привычек**: Попробуйте заменить время, потраченное на фантазии, продуктивной деятельностью — чтением, хобби, физической активностью. Это поможет занять ваш ум и отвлечься от отрыва от реальности.

6. **Общение и поддержка**: Если возможно, обсудите свои трудности с близкими людьми или обратитесь за поддержкой к группам в интернете, где люди сталкиваются с похожими проблемами.

7. **Профессиональная помощь**: Если самоизменения не приносят результатов, обратитесь к психологу или психотерапевту. Специалист может помочь исследовать причины вашего состояния и предложить эффективные терапевтические подходы.

8. **Постановка целей**: Сфокусируйтесь на достижении конкретных целей в реальной жизни, что может повысить мотивацию и снизить потребность в уходе в фантазии.

Помните, изменения требуют времени и усилий. Будьте терпеливы к себе и продолжайте работать над уменьшением влияния навязчивых грёз на вашу жизнь.

turns-00051.parquet:24772

4f678cb9ea77ab340c34f19f
turn 5/6gpt-4o-2024-08-06RussianBelarus95 words
degenerate_repetitionAbsentFinal dense release
USER
Что такое яктация?
ASSISTANT
Яктация — это психомоторное состояние, характеризующееся беспокойством и неугомонными движениями тела, такими как постоянное ворочание в постели или совершение повторяющихся движений. Чаще всего яктация наблюдается у людей, находящихся в состоянии сильного физического или эмоционального стресса, при повышенной температуре тела или в результате некоторых неврологических заболеваний. В некоторых случаях яктация может быть связана с расстройствами сна и наблюдаться у детей в виде раскачивания или тряски перед засыпанием.

Яктация требует внимания, особенно если она приводит к ухудшению качества жизни или является симптомом более серьезного медицинского состояния. В таком случае рекомендуется консультация с медицинским специалистом.

turns-00051.parquet:24773

15ca7cc2259063b2f47e176e
turn 6/6gpt-4o-2024-08-06RussianBelarus119 words
degenerate_repetitionAbsentFinal dense release
USER
У меня с детства привычка раскачиваться на диване, особенно под музыку, это тоже яктация?
ASSISTANT
Привычка раскачиваться на диване, особенно под музыку или в расслабленном состоянии, может быть формой самоуспокаивающего поведения и не обязательно связана с яктацией в её медицинском смысле. Многие люди имеют подобные привычки, которые помогают им концентрироваться или успокаиваться. Это может быть форма стереотипного поведения, которое не всегда говорит о наличии проблем или расстройства.

Если это поведение не вызывает у вас дискомфорта, не мешает повседневной жизни и не связано с какими-либо негативными переживаниями, то беспокоиться, скорее всего, не о чем. Однако, если вам или окружающим кажется, что это поведение мешает или связано с другими трудностями, имеет смысл поговорить об этом с психологом, чтобы получить профессиональную оценку ситуации.

turns-00051.parquet:24774

71919af8b801181291740c2b
turn 1/1gpt-4o-2024-08-06TagalogUnited States507 words
degenerate_repetitionAbsentFinal dense release
USER
Write a educational passage in Vietnamese that could appear in a textbook, giving some paragraphs or pharse that related to this question and answer set:
Câu hỏi: Phát biểu nào không đúng khi nói về thuật toán sắp xếp chọn?
A. Thuật toán thực hiện việc chọn số lớn nhất trong dãy chưa được sắp xếp.
B. Đưa số nhỏ nhất chưa được sắp xếp về vị trí đầu tiên của dãy chưa được sắp xếp.
C. Lặp lại quá trình chọn số nhỏ nhất chưa sắp xếp và đưa về vị trí đầu tiên của dãy cho đến khi dãy chỉ còn một phần tử.
D. Thực hiện sắp xếp dãy phần tử không giảm (hoặc không tăng).
Đáp án đúng: Thuật toán thực hiện việc chọn số lớn nhất trong dãy chưa được sắp xếp.
Notes that:
1. Remember that the multichoice question above must not be included in the paragraphs or phrase
2. You can not take an example same as the question
3. Explain detail like in the actual textbook
4. All instructions must be given in general form
ASSISTANT
Thuật toán sắp xếp chọn (Selection Sort) là một trong những thuật toán sắp xếp cơ bản và dễ hiểu nhất trong lĩnh vực khoa học máy tính. Quá trình của thuật toán này dựa trên việc tìm phần tử nhỏ nhất từ danh sách chưa được sắp xếp và đưa nó về vị trí đầu tiên của danh sách đó. 

Để bắt đầu, thuật toán sẽ duyệt qua toàn bộ danh sách và xác định phần tử có giá trị nhỏ nhất. Một khi phần tử nhỏ nhất được tìm thấy, nó sẽ được hoán đổi vị trí với phần tử đầu tiên của danh sách chưa sắp xếp. Tiếp theo, ta loại bỏ phần tử đầu tiên này ra khỏi danh sách chưa được sắp xếp (xem như đã được sắp xếp), và lặp lại quá trình tìm kiếm phần tử nhỏ nhất trong danh sách mới.

Quá trình này sẽ tiếp tục lặp lại cho đến khi chỉ còn lại một phần tử chưa được sắp xếp, lúc đó toàn bộ danh sách đã trở nên được sắp xếp hoàn toàn. Do đó, thuật toán này có độ phức tạp thời gian là O(n^2), trong đó n là số lượng phần tử cần sắp xếp.

Mặc dù thuật toán sắp xếp chọn không phải là giải pháp hiệu quả nhất cho việc sắp xếp các danh sách lớn, do mức độ phức tạp thời gian khá cao, nhưng nó rất dễ dàng để hiểu và triển khai, đặc biệt hữu ích khi cần sắp xếp những danh sách có kích thước nhỏ. Furthermore, one of its advantages is that it performs well in scenarios where memory write operations are costly, as it makes the minimum number of swaps necessary.

Những đặc điểm này khiến thuật toán sắp xếp chọn là một lựa chọn phù hợp để giảng dạy cho người mới bắt đầu trong lập trình và thuật toán sắp xếp.

turns-00051.parquet:24775

fcb86227384c4c44a7550a43
turn 1/1gpt-4o-2024-08-06VietnameseUnited States1876 words
degenerate_repetitionAbsentFinal dense release
USER
Bạn sẽ nhận được một đoạn ngữ cảnh mô tả một sự kiện hoặc khái niệm cụ thể. Dựa trên ngữ cảnh, hãy tạo ra 3 cặp câu hỏi và câu trả lời đi kèm. Hãy đảm bảo rằng câu trả lời có sự giải thích từng bước hoặc mô tả chi tiết (Chain of Thought) để người đọc hiểu rõ hơn về nội dung câu trả lời.
    Yêu cầu: Tạo 3 cặp câu hỏi và câu trả lời. Hãy lưu ý cung cấp câu trả lời theo từng bước suy luận, hoặc đưa ra các yếu tố giải thích rõ ràng liên quan đến câu trả lời (Chain of Thought). Bước suy luận sẽ lấy thông tin trực tiếp từ ngữ cảnh, thông tin được lấy từ ngữ cảnh sẽ được bỏ vào 2 tag đặc biệt ###begin_context### và ###end_context###. Câu trả lời sẽ ở dạng ngắn gọn, súc tích.

    Câu hỏi được bỏ vào tag ###Câu hỏi:
    Suy luận được bỏ vào tag ###Suy luận:
    Câu trả lời được bỏ vào tag đặc biệt ###Câu trả lời:
    Suy luận bắt buộc phải trích xuất thông tin từ ngữ cảnh và dùng ###begin_context### và ###end_context### để đánh dấu thông tin được trích xuất.

    Nếu ngữ cảnh không có ý nghĩa, bạn hãy output "Ngữ cảnh không giá trị".
    Trả lời bằng tiếng Việt.
    Trả cho tôi output dưới dạng json để có thể trích xuất một cách dễ dàng.

    Ví dụ:
    ###Ngữ cảnh: Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách. Với trên 145 tổ chức thành viên và 65.000 thành viên cá nhân, ISOC bao gồm những con người cụ thể trong cộng đồng Internet. Mọi chi tiết có thể tìm thấy tại website của ISOC.
Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ. Số hội viên của nó bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân. Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.
Nhiệm vụ và mục đích hoạt động.
Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.
    ###Đầu ra: json```{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Internet Society (ISOC) là tổ chức gì và mục tiêu chính của nó là gì?",
            "###Suy luận:": "###begin_context###Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách.###end_context### chỉ ra rằng Internet Society là một tổ chức quốc tế, phi lợi nhuận và phi chính phủ, tập trung vào tiêu chuẩn, giáo dục và các vấn đề chính sách. ###begin_context###Nhiệm vụ và mục đích hoạt động: Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.###end_context### chỉ ra rằng mục tiêu chính của ISOC là bảo đảm và cổ vũ cho sự phát triển, mở rộng và sử dụng Internet thuận lợi nhất cho mọi người trên toàn thế giới.",
            "###Câu trả lời:": "Internet Society (ISOC) là một tổ chức quốc tế phi lợi nhuận và phi chính phủ, nhằm bảo đảm và thúc đẩy sự phát triển, mở rộng và sử dụng Internet một cách thuận lợi cho mọi người trên toàn thế giới."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có quy mô thành viên như thế nào?",
            "###Suy luận:": "###begin_context###Internet Society bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân.###end_context### chỉ ra rằng ISOC có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân. ###begin_context###Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.###end_context### chỉ ra rằng các thành viên còn có thể lập chi nhánh của tổ chức tùy theo vị trí hoặc sở thích, với tổng cộng 90 chi nhánh trên toàn cầu.",
            "###Câu trả lời:": "Internet Society (ISOC) có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân, cùng với 90 chi nhánh trên toàn cầu được thành lập bởi các thành viên theo vị trí hoặc sở thích."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có trụ sở chính ở đâu?",
            "###Suy luận:": "###begin_context###Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ.###end_context### chỉ ra ra rằng ISOC có trụ sở tại hai địa điểm gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ).",
            "###Câu trả lời:": "Internet Society (ISOC) có trụ sở chính gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ)."
        }
    ]
}
```


    Đến lượt bạn:
    ###Ngữ cảnh: Địa bàn tỉnh Gia Lai có một vài cơ sở giáo dục bậc đại học và cao đẳng, bao gồm phân hiệu Trường Đại học Nông Lâm Thành phố Hồ Chí Minh, phân hiệu Trường Đại học Lâm nghiệp, phân hiệu Trường Đại học Sư phạm Thành phố Hồ Chí Minh (được chuyển đổi từ Trường Cao đẳng Sư phạm Gia Lai vào năm 2023), Trường Cao đẳng Gia Lai và Trường Cao đẳng số 21 (trực thuộc Bộ Quốc phòng).
Du lịch.
Tiềm năng du lịch của Gia Lai rất phong phú, đa dạng với núi rùng cao có nhiều cảnh quan tự nhiên và nhân tạo. Rừng nguyên sinh nơi đây có hệ thống động thực vật phong phú, nhiều ghềnh thác, suối, hồ như Biển Hồ (hay Hồ T'Nưng) là một thắng cảnh nổi tiếng, ngoài ra có chùa Minh Thành (Gia Lai). Di tích Đền tưởng niệm liệt sỹ và Tượng đài Chiến thắng Đak Pơ tại huyện Đak Pơ - nơi tưởng niệm các liệt sỹ hi sinh trong trận đánh Đak Pơ. Nhiều đồi núi như cổng trời Mang Yang, đỉnh Hàm Rồng, thác Hang Dơi và thác K50 (Huyện Kbang). Các cảnh quan nhân tạo có các rừng cao su, đồi chè, cà phê bạt ngàn. Kết hợp với tuyến đường rừng, có các tuyến dã ngoại bằng thuyền trên sông, cưỡi voi xuyên rừng,v.v…
Ngoài ra, Gia Lai còn có nền văn hoá lâu đời của đồng bào dân tộc, chủ yếu là dân tộc Gia Rai và Ba Na thể hiện qua kiến trúc nhà rông, nhà sàn, nhà mồ, qua lễ hội truyền thống, qua y phục và nhạc cụ...
Các nhạc cụ đặc trưng của các dân tộc thiểu số như Cồng chiêng, Đàn đá, Đàn K'ni, K'lông pút, Đàn Goong, T'rưng, Alal... Các lễ hội như Lễ hội đâm trâu, Lễ ăn cơm mới, Lễ bỏ mả... Ngoài ra, tỉnh còn có các món đặc sản như Rượu cần, Cơm cháy - Rượu nếp, Phở khô (Loại phở hai tô) và điêu khắc nổi tiếng là Tượng nhà mồ.
    ###Đầu ra:
    
ASSISTANT
```json
{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Tỉnh Gia Lai có những cơ sở giáo dục đại học và cao đẳng nào?",
            "###Suy luận:": "###begin_context###Địa bàn tỉnh Gia Lai có một vài cơ sở giáo dục bậc đại học và cao đẳng, bao gồm phân hiệu Trường Đại học Nông Lâm Thành phố Hồ Chí Minh, phân hiệu Trường Đại học Lâm nghiệp, phân hiệu Trường Đại học Sư phạm Thành phố Hồ Chí Minh (được chuyển đổi từ Trường Cao đẳng Sư phạm Gia Lai vào năm 2023), Trường Cao đẳng Gia Lai và Trường Cao đẳng số 21 (trực thuộc Bộ Quốc phòng).###end_context### chỉ ra rằng Gia Lai có các cơ sở giáo dục đại học và cao đẳng sau: phân hiệu Trường Đại học Nông Lâm Thành phố Hồ Chí Minh, phân hiệu Trường Đại học Lâm nghiệp, phân hiệu Trường Đại học Sư phạm Thành phố Hồ Chí Minh, Trường Cao đẳng Gia Lai và Trường Cao đẳng số 21.",
            "###Câu trả lời:": "Tỉnh Gia Lai có các cơ sở giáo dục đại học và cao đẳng bao gồm phân hiệu Trường Đại học Nông Lâm Thành phố Hồ Chí Minh, phân hiệu Trường Đại học Lâm nghiệp, phân hiệu Trường Đại học Sư phạm Thành phố Hồ Chí Minh, Trường Cao đẳng Gia Lai và Trường Cao đẳng số 21."
        },
        {
            "###Câu hỏi:": "Những điểm du lịch nổi bật nào có tại Gia Lai?",
            "###Suy luận:": "###begin_context###Tiềm năng du lịch của Gia Lai rất phong phú, đa dạng với núi rùng cao có nhiều cảnh quan tự nhiên và nhân tạo. Rừng nguyên sinh nơi đây có hệ thống động thực vật phong phú, nhiều ghềnh thác, suối, hồ như Biển Hồ (hay Hồ T'Nưng) là một thắng cảnh nổi tiếng, ngoài ra có chùa Minh Thành (Gia Lai). Di tích Đền tưởng niệm liệt sỹ và Tượng đài Chiến thắng Đak Pơ tại huyện Đak Pơ. Nhiều đồi núi như cổng trời Mang Yang, đỉnh Hàm Rồng, thác Hang Dơi và thác K50 (Huyện Kbang).###end_context### chỉ ra rằng Gia Lai có Biển Hồ, chùa Minh Thành, Di tích Đền tưởng niệm liệt sỹ và Tượng đài Chiến thắng Đak Pơ, cổng trời Mang Yang, đỉnh Hàm Rồng, thác Hang Dơi và thác K50 là những điểm du lịch nổi bật.",
            "###Câu trả lời:": "Gia Lai có các điểm du lịch nổi bật như Biển Hồ, chùa Minh Thành, Di tích Đền tưởng niệm liệt sỹ và Tượng đài Chiến thắng Đak Pơ, cổng trời Mang Yang, đỉnh Hàm Rồng, thác Hang Dơi và thác K50."
        },
        {
            "###Câu hỏi:": "Các đặc trưng văn hóa của dân tộc thiểu số ở Gia Lai là gì?",
            "###Suy luận:": "###begin_context###Ngoài ra, Gia Lai còn có nền văn hoá lâu đời của đồng bào dân tộc, chủ yếu là dân tộc Gia Rai và Ba Na thể hiện qua kiến trúc nhà rông, nhà sàn, nhà mồ, qua lễ hội truyền thống, qua y phục và nhạc cụ... Các nhạc cụ đặc trưng của các dân tộc thiểu số như Cồng chiêng, Đàn đá, Đàn K'ni, K'lông pút, Đàn Goong, T'rưng, Alal... Các lễ hội như Lễ hội đâm trâu, Lễ ăn cơm mới, Lễ bỏ mả...###end_context### chỉ ra rằng đặc trưng văn hóa của các dân tộc thiểu số ở Gia Lai bao gồm kiến trúc nhà rông, nhà sàn, nhà mồ, lễ hội truyền thống như Lễ hội đâm trâu, Lễ ăn cơm mới, Lễ bỏ mả, và các nhạc cụ như Cồng chiêng, Đàn đá, Đàn K'ni.",
            "###Câu trả lời:": "Đặc trưng văn hóa của dân tộc thiểu số ở Gia Lai bao gồm kiến trúc nhà rông, nhà sàn, nhà mồ, các lễ hội truyền thống như Lễ hội đâm trâu, Lễ ăn cơm mới, Lễ bỏ mả, và nhạc cụ như Cồng chiêng và Đàn đá."
        }
    ]
}
```

turns-00051.parquet:24776

40d14849f6a3d6eabd624492
turn 1/1gpt-4o-2024-08-06EnglishBelgium626 words
degenerate_repetitionAbsentFinal dense release
USER
Create a long detailed text about actor W.C. Fields with the following summary. The title of the video is"20 Most Evil Actors in Hollywood History, here goes my vote..". Stick to the information i give you and dont create new information. Focus only on the Subject name and there following Summary. Subject Name: [W.C. Fields] Summary: [W.C. Fields, known for his comedic talent, had a reputation for being difficult offscreen, with a temper that often clashed with his professional collaborations, reflecting the complexities of his personality beyond his public persona.]

            Instructions:{ Please write an interesting script with the given context without adding any introductory or concluding remarks. 
            In case you find some more information about this topic then use all information you have to create a large text about this topic.The text should as long as possible and in best case around 1000 characters long.
            Ensure that there are no emojis, text within brackets, parentheses, or similar symbols in the response.
            Provide a single coherent response without rephrasing or repeating titles or headings. Avoid enumerations or bullet points. 
            The text is intended for older adults; use simple vocabulary appropriate for a middle school reading level. Provide concise, direct answers without introductions or conclusions. 
            Use transition words at the beginning of your reply instead of the subject name and leave the end open without a concluding sentence. 
            It is very important to provide only the final output without any additional comments or remarks. 
            Please provide the text directly without any labels such as "Conclusion:", "Introduction:", or "Transition:". Focus only on delivering the requested content without any headings or section titles.
            Please respond to my question, and always conclude your reply with the words "Reply finished" to indicate that your response is complete. Make sure the reply is fully contained before these words and is not cut off prematurely. Thank you.}
         Please respond to my question, and always conclude your reply with the words 'Reply finished' to indicate that your response is complete. Ensure that the text is fully formed without any placeholders such as '[Conclusion]' or '[Placeholder]'. Make sure the reply is fully contained before these words and is not cut off prematurely. Thank you.
ASSISTANT
W.C. Fields is remembered as one of the most iconic comedic actors from Hollywood's golden age, renowned for his distinctive voice, witty one-liners, and memorable performances. However, his talent on screen was often juxtaposed with a difficult personality offscreen. Fields was known for his mercurial temper, creating an image of a man whose private life was as complex as the characters he portrayed. Collaborators on film sets frequently found him challenging to work with, as his moods could lead to tensions that disrupted the harmony of professional relationships. Despite these challenges, Fields managed to maintain a successful career, earning a lasting place in the hearts of audiences who appreciated his humor and charm. Yet, his irascible nature and reputation for being difficult marked his legacy, revealing a man whose life offscreen was filled with contradictions and complexities not fully captured by his comedic roles. His reputation for clashing with collaborators was well-known in Hollywood circles, painting the picture of an artist whose personal and professional life was fraught with conflict. His life serves as a testament to the multifaceted nature of human personality, showing that even those who bring laughter to millions might wrestle with their own personal demons. Fields' legacy is a reminder that what we see on screen is often only one layer of an individual's true self. He had a talent for showcasing humor in a way that continues to resonate, yet his behind-the-scenes persona added a layer of intrigue to the public's perception of him, continuing to fascinate those interested in the stories of Hollywood's past. Reply finished.

turns-00051.parquet:24777

38dc33b539bf9b3503cc3de0
turn 1/1gpt-4o-2024-08-06VietnameseBrazil1763 words
degenerate_repetitionAbsentFinal dense release
USER
Bạn sẽ nhận được một đoạn ngữ cảnh mô tả một sự kiện hoặc khái niệm cụ thể. Dựa trên ngữ cảnh, hãy tạo ra 3 cặp câu hỏi và câu trả lời đi kèm. Hãy đảm bảo rằng câu trả lời có sự giải thích từng bước hoặc mô tả chi tiết (Chain of Thought) để người đọc hiểu rõ hơn về nội dung câu trả lời.
    Yêu cầu: Tạo 3 cặp câu hỏi và câu trả lời. Hãy lưu ý cung cấp câu trả lời theo từng bước suy luận, hoặc đưa ra các yếu tố giải thích rõ ràng liên quan đến câu trả lời (Chain of Thought). Bước suy luận sẽ lấy thông tin trực tiếp từ ngữ cảnh, thông tin được lấy từ ngữ cảnh sẽ được bỏ vào 2 tag đặc biệt ###begin_context### và ###end_context###. Câu trả lời sẽ ở dạng ngắn gọn, súc tích.

    Câu hỏi được bỏ vào tag ###Câu hỏi:
    Suy luận được bỏ vào tag ###Suy luận:
    Câu trả lời được bỏ vào tag đặc biệt ###Câu trả lời:
    Suy luận bắt buộc phải trích xuất thông tin từ ngữ cảnh và dùng ###begin_context### và ###end_context### để đánh dấu thông tin được trích xuất.

    Nếu ngữ cảnh không có ý nghĩa, bạn hãy output "Ngữ cảnh không giá trị".
    Trả lời bằng tiếng Việt.
    Trả cho tôi output dưới dạng json để có thể trích xuất một cách dễ dàng.

    Ví dụ:
    ###Ngữ cảnh: Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách. Với trên 145 tổ chức thành viên và 65.000 thành viên cá nhân, ISOC bao gồm những con người cụ thể trong cộng đồng Internet. Mọi chi tiết có thể tìm thấy tại website của ISOC.
Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ. Số hội viên của nó bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân. Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.
Nhiệm vụ và mục đích hoạt động.
Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.
    ###Đầu ra: json```{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Internet Society (ISOC) là tổ chức gì và mục tiêu chính của nó là gì?",
            "###Suy luận:": "###begin_context###Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách.###end_context### chỉ ra rằng Internet Society là một tổ chức quốc tế, phi lợi nhuận và phi chính phủ, tập trung vào tiêu chuẩn, giáo dục và các vấn đề chính sách. ###begin_context###Nhiệm vụ và mục đích hoạt động: Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.###end_context### chỉ ra rằng mục tiêu chính của ISOC là bảo đảm và cổ vũ cho sự phát triển, mở rộng và sử dụng Internet thuận lợi nhất cho mọi người trên toàn thế giới.",
            "###Câu trả lời:": "Internet Society (ISOC) là một tổ chức quốc tế phi lợi nhuận và phi chính phủ, nhằm bảo đảm và thúc đẩy sự phát triển, mở rộng và sử dụng Internet một cách thuận lợi cho mọi người trên toàn thế giới."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có quy mô thành viên như thế nào?",
            "###Suy luận:": "###begin_context###Internet Society bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân.###end_context### chỉ ra rằng ISOC có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân. ###begin_context###Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.###end_context### chỉ ra rằng các thành viên còn có thể lập chi nhánh của tổ chức tùy theo vị trí hoặc sở thích, với tổng cộng 90 chi nhánh trên toàn cầu.",
            "###Câu trả lời:": "Internet Society (ISOC) có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân, cùng với 90 chi nhánh trên toàn cầu được thành lập bởi các thành viên theo vị trí hoặc sở thích."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có trụ sở chính ở đâu?",
            "###Suy luận:": "###begin_context###Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ.###end_context### chỉ ra ra rằng ISOC có trụ sở tại hai địa điểm gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ).",
            "###Câu trả lời:": "Internet Society (ISOC) có trụ sở chính gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ)."
        }
    ]
}
```


    Đến lượt bạn:
    ###Ngữ cảnh: Viết "lá vằng" không dấu thành La Vang.
Một thuyết khác cho là địa danh "phường Lá Vắng" đã có từ trước đó, thuộc làng Cổ Vưu, nằm về phía Tây cách đồn Dinh Cát, về sau là tỉnh lỵ Quảng Trị, 4 cây số và cách Phú Xuân, tức Kinh Đô [[Huế]], 58 km về phía Bắc.
Đức Mẹ hiển linh.
[[Tập tin:VN Phat Diem tango7174.jpg|nhỏ|trái|262x262px|Tượng Đức Mẹ La Vang tại [[nhà thờ Phát Diệm]]]]
Theo "Tư liệu Tòa Tổng Giám mục Huế - 1998", dưới triều đại vua [[Cảnh Thịnh]] (lên ngôi năm 1792), với chiếu chỉ cấm đạo ngày 17 tháng 8 năm 1798, một số các tín hữu ở gần đồi Dinh Cát (nay là [[thị xã Quảng Trị]]) phải tìm nơi trốn ẩn. Họ đã đến lánh nạn tại núi rừng La Vang. Nơi rừng thiêng nước độc, hoàn cảnh ngặt nghèo, thiếu ăn, bệnh tật, sợ hãi quan quân, sợ thú dữ, các tín hữu chỉ biết một lòng tin cậy phó thác vào [[Thiên Chúa]] và [[Đức Mẹ]]. Họ thường tụ tập nhau dưới gốc cây đa cổ thụ, cùng nhau cầu nguyện, an ủi và giúp đỡ nhau.
Một hôm đang khi cùng nhau lần [[Kinh Mân Côi|chuỗi Mân Côi]] kính Đức Mẹ, bỗng họ nhìn thấy một người phụ nữ xinh đẹp, mặc áo choàng rộng, tay bồng Chúa Hài Đồng [[Giêsu]], có hai thiên thần cầm đèn chầu hai bên. Họ nhận ra ngay là Mẹ Maria. Mẹ bày tỏ lòng nhân từ, âu yếm, và an ủi giáo dân vui lòng chịu khó. Mẹ dạy hái một loại lá cây có sẵn chung quanh đó, đem nấu nước uống sẽ lành các chứng bệnh. Mẹ lại ban lời hứa: "Mẹ đã nhận lời các con kêu xin. Từ nay về sau, hễ ai chạy đến cầu khẩn Mẹ tại chốn này, Mẹ sẽ nhận lời ban ơn theo ý nguyện".
Sự kiện xảy ra trên thảm cỏ gần gốc cây đa cổ thụ nơi giáo dân đang cầu nguyện. Sau đó, Mẹ còn hiện ra nhiều lần như vậy để nâng đỡ và an ủi con cái Mẹ trong cơn hoạn nạn.
Từ đó đến nay sự kiện Đức Mẹ hiện ra tại núi rừng La Vang, qua các thế hệ được loan truyền khắp nơi, và nhiều người chân thành tin tưởng, đến cầu khấn Đức Mẹ.
    ###Đầu ra:
    
ASSISTANT
```json
{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Sự kiện gì đã xảy ra tại núi rừng La Vang theo tài liệu lịch sử?",
            "###Suy luận:": "###begin_context###Dưới triều đại vua Cảnh Thịnh, với chiếu chỉ cấm đạo ngày 17 tháng 8 năm 1798, một số các tín hữu ở gần đồi Dinh Cát phải tìm nơi trốn ẩn và đã đến lánh nạn tại núi rừng La Vang. Trong hoàn cảnh ngặt nghèo, họ đã cầu nguyện dưới gốc cây đa cổ thụ và chứng kiến một người phụ nữ xinh đẹp mặc áo choàng rộng hiện ra. Họ nhận ra đó là Đức Mẹ Maria. Mẹ đã âu yếm an ủi và dạy họ dùng lá cây xung quanh để chữa bệnh. Mẹ cũng hứa ban ơn cho những ai cầu khẩn Mẹ tại đó.###end_context### chỉ ra rằng tại núi rừng La Vang, các tín hữu đã chứng kiến hiện tượng Đức Mẹ Maria hiện ra để an ủi và hướng dẫn họ tránh bệnh tật. Sự kiện này đã được truyền bá rộng rãi qua các thế hệ.",
            "###Câu trả lời:": "Tại núi rừng La Vang, các tín hữu gặp sự hiện diện của Đức Mẹ Maria, người đã an ủi và dạy họ cách chữa bệnh, đồng thời hứa ban ơn cho những ai cầu khẩn bà ở đó."
        },
        {
            "###Câu hỏi:": "Làm thế nào các tín hữu tại La Vang đã xử lý tình hình khó khăn mà họ gặp phải?",
            "###Suy luận:": "###begin_context###Các tín hữu tại La Vang đối mặt với hoàn cảnh ngặt nghèo, thiếu ăn, bệnh tật, và sợ hãi nhưng đã cầu nguyện dưới gốc cây đa cổ thụ. Họ đã nhận được lời khuyên từ Đức Mẹ Maria, người hiện ra và chỉ dẫn cách sử dụng lá cây xung quanh để nấu nước uống chữa bệnh.###end_context### chỉ ra rằng các tín hữu đã dùng sự hướng dẫn của Đức Mẹ để đối phó với bệnh tật bằng cách sử dụng lá cây xung quanh núi rừng La Vang.",
            "###Câu trả lời:": "Các tín hữu tại La Vang đã cầu nguyện và nhận hướng dẫn từ Đức Mẹ để sử dụng lá cây nấu nước uống nhằm chữa bệnh."
        },
        {
            "###Câu hỏi:": "Đức Mẹ đã đưa ra lời hứa gì với các tín hữu tại La Vang?",
            "###Suy luận:": "###begin_context###Mẹ Maria bày tỏ lòng nhân từ, âu yếm, và an ủi giáo dân, đồng thời ban lời hứa rằng \"Mẹ đã nhận lời các con kêu xin. Từ nay về sau, hễ ai chạy đến cầu khẩn Mẹ tại chốn này, Mẹ sẽ nhận lời ban ơn theo ý nguyện\".###end_context### chỉ ra rằng Đức Mẹ hứa ban ơn cho bất kỳ ai cầu khẩn tại La Vang.",
            "###Câu trả lời:": "Đức Mẹ hứa rằng bất kỳ ai cầu khẩn bà tại La Vang sẽ được nhận lời và ban ơn theo ý nguyện."
        }
    ]
}
```

turns-00051.parquet:24778

8ecd0008e6a79ca9a4b66010
turn 1/1gpt-4o-2024-08-06Vietnameseunknown country2167 words
degenerate_repetitionAbsentFinal dense release
USER
Bạn sẽ nhận được một đoạn ngữ cảnh mô tả một sự kiện hoặc khái niệm cụ thể. Dựa trên ngữ cảnh, hãy tạo ra 3 cặp câu hỏi và câu trả lời đi kèm. Hãy đảm bảo rằng câu trả lời có sự giải thích từng bước hoặc mô tả chi tiết (Chain of Thought) để người đọc hiểu rõ hơn về nội dung câu trả lời.
    Yêu cầu: Tạo 3 cặp câu hỏi và câu trả lời. Hãy lưu ý cung cấp câu trả lời theo từng bước suy luận, hoặc đưa ra các yếu tố giải thích rõ ràng liên quan đến câu trả lời (Chain of Thought). Bước suy luận sẽ lấy thông tin trực tiếp từ ngữ cảnh, thông tin được lấy từ ngữ cảnh sẽ được bỏ vào 2 tag đặc biệt ###begin_context### và ###end_context###. Câu trả lời sẽ ở dạng ngắn gọn, súc tích.

    Câu hỏi được bỏ vào tag ###Câu hỏi:
    Suy luận được bỏ vào tag ###Suy luận:
    Câu trả lời được bỏ vào tag đặc biệt ###Câu trả lời:
    Suy luận bắt buộc phải trích xuất thông tin từ ngữ cảnh và dùng ###begin_context### và ###end_context### để đánh dấu thông tin được trích xuất.

    Nếu ngữ cảnh không có ý nghĩa, bạn hãy output "Ngữ cảnh không giá trị".
    Trả lời bằng tiếng Việt.
    Trả cho tôi output dưới dạng json để có thể trích xuất một cách dễ dàng.

    Ví dụ:
    ###Ngữ cảnh: Tìm hiểu về nguyên nhân, triệu chứng và các phương pháp chữa hở mi mắt
Không chỉ mang tính thẩm mỹ, mi mắt còn có tác dụng bảo vệ đôi mắt khỏi các yếu tố bên ngoài. Nếu bộ phận này không thể đóng kín hoàn toàn thì hoạt động của mắt có thể bị ảnh hưởng. Vậy, bạn nên làm gì để chữa hở mi mắt? Hãy cùng chúng tôi theo dõi bài viết dưới đây để tìm hiểu một cách chi tiết về nguyên nhân, triệu chứng và các giải pháp khắc phục tình trạng này nhé!
1. Hở mi mắt là gì?
Đôi mắt là cửa sổ tâm hồn, là cơ quan tiếp nhận ánh sáng giúp con người nhìn thấy mọi vật xung quanh. Tuy nhiên, cơ quan này rất nhạy cảm và dễ bị tổn thương bởi các tác động của môi trường. Do đó, các thành phần bên trong mắt nhất là giác mạc cần được bảo vệ và che chở bởi các bộ phận khác như: lông mày, lông mi,…
Đặc biệt, mi mắt có thể tự động đóng kín nhằm ngăn chặn bụi bẩn, các vật lạ bay vào. Đồng thời thông qua phản xạ chớp mi liên tục, tuyến lệ sẽ điều tiết nước mắt và dàn đều khắp lòng đen và lòng trắng. Do đó, mắt được cung cấp đầy đủ độ ẩm nên luôn trơn ướt, không bị khô và nhìn ngắm mọi vật một cách rõ ràng.
Trong trường hợp bị hở, mi mắt sẽ không thể khép kín hoàn toàn như bình thường. Lúc này chức năng bảo vệ giảm sút, dị vật, bụi bẩn,… bên ngoài có thể xâm nhập vào mắt gây tổn thương và nhiễm trùng, từ đó ảnh hưởng nghiêm trọng đến thị lực.
Nguyên nhân:
Nguyên nhân gây hở mi mắt rất phức tạp, để có biện pháp khắc phục hiệu quả bạn nên tìm hiểu lý do tại sao mi mắt của mình không thể khép kín hoàn toàn.
Dây thần kinh vận động của mi mắt bị liệt, gây ảnh hưởng đến phản xạ đóng, mở tự nhiên.
Chấn thương mạnh làm tổn thương cơ mặt, cấu trúc tại vùng mắt,…
Rối loạn giấc ngủ, thiếu ngủ, mất ngủ cũng ảnh hưởng đến phản xạ khép mở mi mắt.
Mắc phải các bệnh về mắt như: lồi hoặc lõm mắt, có sẹo, khối u trong mắt,…
Thực hiện phẫu thuật thẩm mỹ cắt da thừa, lấy mỡ mắt nhưng gặp biến chứng ngay sau đó.
    ###Đầu ra: json```{
    "QA_pairs": [
        {
        "###Câu hỏi:": "Hở mi mắt là gì và nó ảnh hưởng như thế nào đến mắt?",
        "###Suy luận:": "Theo ngữ cảnh, hở mi mắt là khi mi mắt không thể khép kín hoàn toàn. ###begin_context###Trong trường hợp bị hở, mi mắt sẽ không thể khép kín hoàn toàn như bình thường. Lúc này chức năng bảo vệ giảm sút, dị vật, bụi bẩn,… bên ngoài có thể xâm nhập vào mắt gây tổn thương và nhiễm trùng, từ đó ảnh hưởng nghiêm trọng đến thị lực.###end_context### chỉ ra rằng hở mi mắt ảnh hưởng đến mắt bằng cách giảm khả năng bảo vệ và tăng nguy cơ tổn thương, nhiễm trùng.",
        "###Câu trả lời:": "Hở mi mắt là tình trạng mi mắt không thể khép kín hoàn toàn, làm giảm chức năng bảo vệ của mắt, dẫn đến nguy cơ dị vật, bụi bẩn xâm nhập, gây tổn thương và nhiễm trùng, ảnh hưởng nghiêm trọng đến thị lực."
        },
        {
        "###Câu hỏi:": "Những nguyên nhân nào gây ra hở mi mắt?",
        "###Suy luận:": "###begin_context###Nguyên nhân gây hở mi mắt rất phức tạp, để có biện pháp khắc phục hiệu quả bạn nên tìm hiểu lý do tại sao mi mắt của mình không thể khép kín hoàn toàn.
Dây thần kinh vận động của mi mắt bị liệt, gây ảnh hưởng đến phản xạ đóng, mở tự nhiên.
Chấn thương mạnh làm tổn thương cơ mặt, cấu trúc tại vùng mắt,…
Rối loạn giấc ngủ, thiếu ngủ, mất ngủ cũng ảnh hưởng đến phản xạ khép mở mi mắt.
Mắc phải các bệnh về mắt như: lồi hoặc lõm mắt, có sẹo, khối u trong mắt,…
Thực hiện phẫu thuật thẩm mỹ cắt da thừa, lấy mỡ mắt nhưng gặp biến chứng ngay sau đó.###end_context### chỉ ra rằng những nguyên nhân chính gây ra hở mi mắt bao gồm dây thần kinh vận động của mi mắt bị liệt; chấn thương mạnh làm tổn thương cơ mặt, cấu trúc tại vùng mắt; rối loạn giấc ngủ, thiếu ngủ, mất ngủ; mắc phải các bệnh về mắt như: lồi hoặc lõm mắt, có sẹo, khối u trong mắt.",
        "###Câu trả lời:": "Những nguyên nhân gây hở mi mắt bao gồm: liệt dây thần kinh vận động của mi mắt, chấn thương mạnh làm tổn thương cơ mặt hoặc cấu trúc vùng mắt, rối loạn giấc ngủ như thiếu ngủ hoặc mất ngủ, mắc các bệnh về mắt như lồi hoặc lõm mắt, có sẹo, khối u trong mắt, và biến chứng sau phẫu thuật thẩm mỹ vùng mắt."
        },
        {
        "###Câu hỏi:": "Mi mắt đóng kín có vai trò gì trong việc bảo vệ mắt?",
        "###Suy luận:": "Mi mắt đóng kín giúp ngăn chặn bụi bẩn và dị vật bay vào mắt. ###begin_context###Đặc biệt, mi mắt có thể tự động đóng kín nhằm ngăn chặn bụi bẩn, các vật lạ bay vào. Đồng thời thông qua phản xạ chớp mi liên tục, tuyến lệ sẽ điều tiết nước mắt và dàn đều khắp lòng đen và lòng trắng. Do đó, mắt được cung cấp đầy đủ độ ẩm nên luôn trơn ướt, không bị khô và nhìn ngắm mọi vật một cách rõ ràng.###end_context### chỉ ra rằng mi mắt đóng kín bảo vệ mắt khỏi các yếu tố bên ngoài và giữ ẩm cho mắt.",
        "###Câu trả lời:": "Mi mắt đóng kín có vai trò ngăn chặn bụi bẩn và dị vật xâm nhập vào mắt, đồng thời giúp tuyến lệ điều tiết nước mắt, giữ ẩm cho mắt và duy trì thị lực rõ ràng."
        }
    ]
}
```


    Đến lượt bạn:
    ###Ngữ cảnh: Liều lượng của hầu hết các loại thuốc này có thể giảm 10% sau mỗi hai tuần.
 2.3. Cẩn thận khi sử dụng thuốc
 – Chờ đủ thời gian để đánh giá hiệu quả điều trị: vài ngày dùng ethanol, benzodiazepin; 2 đến 3 tuần dùng phenobarbital, phenytoin; vài tuần dùng acid valproic.
– Hiểu rõ tác dụng phụ, phản ứng có hại của từng loại thuốc để theo dõi kịp thời. Nếu bệnh nhân bị ngộ độc thuốc trước khi kiểm soát cơn động kinh, hãy giảm liều xuống thấp hơn liều gây độc trước đó.
Sau đó, một loại thuốc khác được thêm vào với liều thấp, tăng dần liều cho đến khi cơn động kinh được kiểm soát. Cần theo dõi bệnh nhân chặt chẽ vì hai loại thuốc này có thể tương tác và ảnh hưởng đến tốc độ chuyển hóa và thoái hóa của một trong hai loại thuốc. Trước tiên nên giảm liều từ từ và sau đó ngừng hẳn.
– Nếu có thể, kiểm tra nồng độ thuốc trong máu nếu cần thiết. Liều thích hợp của thuốc là liều thấp nhất có thể ngăn chặn tất cả các cơn động kinh với tác dụng phụ tối thiểu, bất kể nồng độ của thuốc trong máu. Nồng độ trong huyết tương chỉ là hướng dẫn điều trị. Khi phản ứng thuốc xảy ra, việc đánh giá lâm sàng tiếp theo sẽ hữu ích hơn việc đo nồng độ thuốc trong máu.
 Người bệnh cần sử dụng thuốc theo hướng dẫn của bác sĩ.
 3. Khi nào có thể ngừng điều trị bệnh động kinh?
 Một vài trường hợp, hoàn cảnh có thể đặt vấn đề ngừng điều trị động kinh. Ví dụ, khi có chẩn đoán rõ ràng là động kinh thì có thể thận trọng giảm dần liều rồi tiến đến cắt hẳn thuốc, đồng thời cảnh giác nếu xảy ra tình trạng này.
Một số thể lâm sàng có thể ngừng điều trị như:
– Động kinh kịch phát ở vùng đỉnh
– Động kinh cơn nhỏ ở trẻ em,
– Động kinh toàn bộ nguyên phát cơn lớn ở thiếu niên (thường xảy ra 2 – 3 lần một năm)
– Động kinh hoàn toàn nguyên phát cơn lớn ở trẻ vị thành niên
– Động kinh sau chấn thương không tiến triển và không nghiêm trọng lắm…
Việc dừng điều trị động kinh phải được thầy thuốc chuyên khoa xem xét và quyết định.
    ###Đầu ra:
    
ASSISTANT
```json
{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Quy trình giảm liều thuốc trong điều trị động kinh được thực hiện như thế nào?",
            "###Suy luận:": "Theo ngữ cảnh, việc giảm liều thuốc trong điều trị động kinh được thực hiện từ từ và có thể cần phải ngừng hẳn nếu điều kiện cho phép. ###begin_context###Trước tiên nên giảm liều từ từ và sau đó ngừng hẳn.###end_context### chỉ ra quy trình giảm liều từ từ trước khi ngưng hoàn toàn, và việc này cần được thực hiện dựa trên sự giám sát của bác sĩ chuyên khoa.",
            "###Câu trả lời:": "Quy trình giảm liều thuốc trong điều trị động kinh cần được thực hiện từ từ và có thể ngưng hoàn toàn nếu điều kiện cho phép, theo hướng dẫn của bác sĩ chuyên khoa."
        },
        {
            "###Câu hỏi:": "Có nên kiểm tra nồng độ thuốc trong máu khi điều trị động kinh không?",
            "###Suy luận:": "Ngữ cảnh cho thấy kiểm tra nồng độ thuốc trong máu có thể cần thiết nhưng không phải là yếu tố quyết định trong điều trị hiệu quả động kinh. ###begin_context###Nếu có thể, kiểm tra nồng độ thuốc trong máu nếu cần thiết. Nồng độ trong huyết tương chỉ là hướng dẫn điều trị. Khi phản ứng thuốc xảy ra, việc đánh giá lâm sàng tiếp theo sẽ hữu ích hơn việc đo nồng độ thuốc trong máu.###end_context### cho thấy rằng đánh giá lâm sàng có thể quan trọng hơn trong trường hợp xảy ra phản ứng thuốc.",
            "###Câu trả lời:": "Kiểm tra nồng độ thuốc trong máu có thể cần thiết nhưng không quyết định. Đánh giá lâm sàng khi xảy ra phản ứng thuốc là hữu ích hơn."
        },
        {
            "###Câu hỏi:": "Những trường hợp nào có thể ngưng điều trị động kinh?",
            "###Suy luận:": "Ngữ cảnh liệt kê một số tình huống lâm sàng có thể cân nhắc ngưng điều trị động kinh. ###begin_context###Một số thể lâm sàng có thể ngừng điều trị như: Động kinh kịch phát ở vùng đỉnh, Động kinh cơn nhỏ ở trẻ em, Động kinh toàn bộ nguyên phát cơn lớn ở thiếu niên (thường xảy ra 2 – 3 lần một năm), Động kinh hoàn toàn nguyên phát cơn lớn ở trẻ vị thành niên, Động kinh sau chấn thương không tiến triển và không nghiêm trọng lắm.###end_context### cho thấy những thể lâm sàng như động kinh kịch phát ở vùng đỉnh và một số trường hợp khác có thể là tình huống nên cân nhắc ngưng điều trị.",
            "###Câu trả lời:": "Có thể ngưng điều trị động kinh trong các trường hợp như động kinh kịch phát ở vùng đỉnh, động kinh cơn nhỏ ở trẻ em, và một số tình huống cụ thể khác theo tư vấn của bác sĩ."
        }
    ]
}
```

turns-00051.parquet:24779

df759990fc747d54a8c59dcb
turn 1/1o1-mini-2024-09-12EnglishSouth Korea10073 words
degenerate_repetitionAbsentFinal dense release
USER
// ==UserScript==
// @name         종합 웹 크롤러 7.6 Enhanced
// @namespace    http://tampermonkey.net/
// @version      7.6
// @description  고급 기능을 갖춘 웹 크롤러로 검색 결과를 실시간으로 수집하고 표시 (무제한 페이지 지원 및 기능 개선)
// @author       YourName
// @match        *://www.google.com/search*
// @match        *://www.bing.com/search*
// @match        *://search.daum.net/search*
// @match        *://search.naver.com/search*
// @match        *://search.yahoo.com/search*
// @match        *://duckduckgo.com/*
// @match        *://www.ecosia.org/search*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_notification
// @connect      *
// @require      https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// @require      https://cdn.jsdelivr.net/npm/chart.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js
// ==/UserScript==

(function() {
    'use strict';

    // CSS 스타일 추가 (크롤러 창 대폭 개선)
    GM_addStyle(`
        /* 기본 컨테이너 스타일 */
        #crawler-container {
            position: fixed;
            top: 50px;
            right: 50px;
            background-color: #1e1e1e;
            border: 2px solid #4CAF50;
            padding: 20px;
            z-index: 10000;
            width: 700px;
            max-height: 90vh;
            overflow: hidden;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            border-radius: 10px;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 14px;
            display: flex;
            flex-direction: column;
            transition: all 0.3s ease;
            color: #fff;
        }

        /* 헤더 스타일 */
        #crawler-container header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            background-color: #2d2d30;
            color: #fff;
            padding: 10px 15px;
            border-radius: 8px 8px 0 0;
            cursor: move;
        }

        #crawler-container header .title {
            font-size: 20px;
            font-weight: bold;
        }

        #crawler-container header .close-btn {
            font-size: 24px;
            cursor: pointer;
            transition: color 0.3s;
        }

        #crawler-container header .close-btn:hover {
            color: #ff4d4d;
        }

        /* 탭 스타일 */
        #crawler-container .tabs {
            display: flex;
            border-bottom: 2px solid #4CAF50;
            margin-top: 15px;
        }

        #crawler-container .tab {
            flex: 1;
            padding: 10px;
            text-align: center;
            cursor: pointer;
            background-color: #2d2d30;
            transition: background-color 0.3s, color 0.3s;
            border-right: 1px solid #4CAF50;
        }

        #crawler-container .tab:last-child {
            border-right: none;
        }

        #crawler-container .tab.active {
            background-color: #4CAF50;
            color: #fff;
            font-weight: bold;
            border-bottom: 2px solid #fff;
        }

        /* 탭 콘텐츠 스타일 */
        #crawler-container .tab-content {
            display: none;
            padding: 15px;
            flex-grow: 1;
            overflow-y: auto;
            background-color: #1e1e1e;
        }

        #crawler-container .tab-content.active {
            display: block;
        }

        /* 버튼 스타일 */
        #crawler-container button {
            padding: 8px 12px;
            margin: 6px 4px;
            border: none;
            border-radius: 5px;
            background-color: #4CAF50;
            color: #fff;
            cursor: pointer;
            transition: background-color 0.3s;
            font-size: 14px;
            display: flex;
            align-items: center;
        }

        #crawler-container button:hover {
            background-color: #45a049;
        }

        #crawler-container button i {
            margin-right: 6px;
            font-size: 16px;
        }

        /* Toggle 스위치 스타일 */
        .switch {
          position: relative;
          display: inline-block;
          width: 50px;
          height: 24px;
          margin-left: 10px;
          vertical-align: middle;
        }

        .switch input {
          opacity: 0;
          width: 0;
          height: 0;
        }

        .slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: #ccc;
          transition: .4s;
          border-radius: 24px;
        }

        .slider:before {
          position: absolute;
          content: "";
          height: 18px;
          width: 18px;
          left: 3px;
          bottom: 3px;
          background-color: white;
          transition: .4s;
          border-radius: 50%;
        }

        input:checked + .slider {
          background-color: #4CAF50;
        }

        input:focus + .slider {
          box-shadow: 0 0 1px #4CAF50;
        }

        input:checked + .slider:before {
          transform: translateX(26px);
        }

        /* 기타 섹션 스타일 */
        #crawler-container .options,
        #crawler-container .filters,
        #crawler-container .exclude-domains,
        #crawler-container .advanced-options,
        #crawler-container .site-filters,
        #crawler-container .controls,
        #crawler-container .site-filter-settings {
            margin-bottom: 20px;
        }

        /* 입력 필드 스타일 */
        #crawler-container input[type="text"],
        #crawler-container textarea,
        #crawler-container input[type="number"],
        #crawler-container select {
            width: 100%;
            padding: 8px;
            margin-top: 5px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 14px;
            background-color: #2d2d30;
            color: #fff;
        }

        #crawler-container input[type="text"]::placeholder,
        #crawler-container textarea::placeholder {
            color: #aaa;
        }

        /* 테이블 스타일 */
        #crawler-container table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
            font-size: 13px;
            background-color: #1e1e1e;
        }

        #crawler-container th, #crawler-container td {
            border: 1px solid #4CAF50;
            padding: 8px;
            text-align: left;
            vertical-align: middle;
        }

        #crawler-container th {
            background-color: #4CAF50;
            color: #fff;
            position: sticky;
            top: 0;
            z-index: 2;
        }

        /* 로그 섹션 스타일 */
        #crawler-container .log {
            max-height: 150px;
            overflow-y: auto;
            background-color: #2d2d30;
            padding: 10px;
            border: 1px solid #4CAF50;
            border-radius: 5px;
            font-size: 13px;
            white-space: pre-wrap;
        }

        /* 진행률 표시줄과 상태 텍스트 */
        #crawler-container .progress-section {
            display: flex;
            align-items: center;
            margin-top: 10px;
        }

        #crawler-container progress {
            flex: 1;
            height: 20px;
            margin-right: 10px;
        }

        #crawler-container .status {
            font-size: 14px;
            font-weight: bold;
            margin-top: 10px;
        }

        /* 차트 컨테이너 */
        #crawler-container .chart-container {
            position: relative;
            height: 250px;
            margin-top: 20px;
            background-color: #2d2d30;
            padding: 10px;
            border-radius: 5px;
        }

        /* 미리보기 팝업 스타일 */
        .preview-popup {
            position: absolute;
            top: 0;
            left: 0;
            width: 400px;
            height: 300px;
            background-color: #1e1e1e;
            border: 2px solid #4CAF50;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            z-index: 10001;
            display: none;
            border-radius: 8px;
            overflow: hidden;
        }

        /* iframe 스타일 */
        .html-display {
            width: 100%;
            height: 500px;
            border: 2px solid #4CAF50;
            border-radius: 8px;
            margin-top: 20px;
            background-color: #fff;
            display: none;
        }

        /* 검색 엔진 팝업 스타일 */
        .search-engine-popup {
            position: absolute;
            top: 60px;
            right: 20px;
            width: 200px;
            background-color: #2d2d30;
            border: 2px solid #4CAF50;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            z-index: 10002;
            display: none;
            border-radius: 8px;
            padding: 10px;
        }

        .search-engine-popup button {
            width: 100%;
            margin-bottom: 10px;
            background-color: #4CAF50;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .search-engine-popup button:last-child {
            margin-bottom: 0;
        }

        /* 반응형 디자인 */
        @media (max-width: 800px) {
            #crawler-container {
                width: 95%;
                right: 2.5%;
            }

            .preview-popup {
                width: 90%;
                height: 200px;
            }

            .html-display {
                height: 300px;
            }
        }
    `);

    // UI 생성 (대폭 개선된 디자인)
    const container = document.createElement('div');
    container.id = 'crawler-container';
    container.innerHTML = `
        <header>
            <span class="title">🔥 웹 크롤러 7.6</span>
            <span class="close-btn" title="닫기">&times;</span>
        </header>
        <div class="tabs">
            <div class="tab active" data-tab="settings">설정</div>
            <div class="tab" data-tab="results">결과</div>
            <div class="tab" data-tab="logs">로그</div>
            <div class="tab" data-tab="site-filters">사이트 필터</div>
        </div>
        <div class="tab-content active" id="settings">
            <!-- 제어 버튼 -->
            <div class="controls">
                <button id="startBtn" title="크롤링 시작"><i>▶️</i> 시작</button>
                <button id="pauseBtn" class="pause-btn" title="크롤링 일시정지/재개"><i>⏸️</i> 일시정지</button>
                <button id="stopBtn" title="크롤링 중지"><i>⏹️</i> 중지</button>
                <button id="resetBtn" title="크롤링 초기화"><i>🔄</i> 초기화</button>
                <button id="exportBtn" class="export-btn" title="결과 내보내기"><i>💾</i> 내보내기</button>
                <button id="searchEnginesBtn" class="search-engines-btn" title="검색 엔진 바로가기"><i>🔍</i> 검색 엔진</button>
            </div>
            <!-- 옵션 섹션 -->
            <div class="options">
                <label><input type="checkbox" id="toggleHTML" checked> HTML 가져오기</label>
                <label><input type="checkbox" id="toggleImages" checked> 이미지 가져오기</label>
                <label><input type="checkbox" id="toggleAds" checked> 광고 제외</label>
            </div>
            <!-- 사이트 필터링 섹션 -->
            <div class="site-filter-settings">
                <label>사이트 필터링 기능
                    <label class="switch">
                        <input type="checkbox" id="enableSiteFiltering" checked>
                        <span class="slider"></span>
                    </label>
                </label>
            </div>
            <!-- 필터 섹션 -->
            <div class="filters">
                <label for="filterInput">필터 단어 (정규식, 쉼표로 구분):</label>
                <input type="text" id="filterInput" placeholder="예: 기부, 광고, /promo/i">
            </div>
            <!-- 도메인 제외 섹션 -->
            <div class="exclude-domains">
                <label for="excludeDomainsInput">제외할 도메인 (쉼표로 구분):</label>
                <input type="text" id="excludeDomainsInput" placeholder="예: facebook.com, youtube.com">
            </div>
            <!-- 고급 옵션 섹션 -->
            <div class="advanced-options">
                <label for="duplicateThreshold">중복 허용 횟수:</label>
                <input type="number" id="duplicateThreshold" value="2" min="1" style="width: 60px;">
                <label for="retryAttempts">재시도 횟수:</label>
                <input type="number" id="retryAttempts" value="3" min="1" style="width: 60px;">
                <label for="retryInterval">재시도 간격 (ms):</label>
                <input type="number" id="retryInterval" value="500" min="100" style="width: 80px;">
            </div>
            <!-- 진행률 표시 섹션 -->
            <div class="progress-section">
                <progress id="progressBar" value="0" max="100"></progress>
                <span id="progressText">0%</span>
            </div>
            <!-- 상태 정보 섹션 -->
            <div class="status">
                현재 페이지: <span id="currentPage">0</span>
                <br>
                방문된 사이트: <span id="visitedCount">0</span>
                <br>
                경과 시간: <span id="elapsedTime">00:00:00</span>
                <br>
                예상 남은 시간: <span id="remainingTime">00:00:00</span>
            </div>
            <!-- 차트 섹션 -->
            <div class="chart-container">
                <canvas id="crawlChart"></canvas>
            </div>
        </div>
        <div class="tab-content" id="results">
            <div style="margin-top:10px; overflow: auto;">
                <table id="resultsTable">
                    <thead>
                        <tr>
                            <th>사이트 이름</th>
                            <th>주소</th>
                            <th>설명</th>
                            <th>이미지</th>
                            <th>HTML 링크</th>
                            <th>페이지 로딩 시간 (ms)</th>
                        </tr>
                    </thead>
                    <tbody id="resultsBody">
                    </tbody>
                </table>
                <iframe class="html-display" src=""></iframe>
            </div>
        </div>
        <div class="tab-content" id="logs">
            <div class="log" id="log">
                <strong>로그:</strong>
            </div>
        </div>
        <div class="tab-content" id="site-filters">
            <div class="site-filters">
                <label for="siteFilterInput">추가 사이트 필터링 단어 (제목 또는 내용 포함 시 제외, 정규식 지원):</label>
                <input type="text" id="siteFilterInput" placeholder="예: 기부, 광고, /promo/i">
            </div>
        </div>
        <div class="search-engine-popup">
            <button class="search-engine-btn" data-url="https://www.google.com/">Google</button>
            <button class="search-engine-btn" data-url="https://www.bing.com/">Bing</button>
            <button class="search-engine-btn" data-url="https://www.daum.net/">Daum</button>
            <button class="search-engine-btn" data-url="https://www.naver.com/">Naver</button>
            <button class="search-engine-btn" data-url="https://www.yahoo.com/">Yahoo</button>
            <button class="search-engine-btn" data-url="https://duckduckgo.com/">DuckDuckGo</button>
            <button class="search-engine-btn" data-url="https://www.ecosia.org/">Ecosia</button>
        </div>
    `;
    document.body.appendChild(container);

    // 드래그 가능하게 설정
    (function makeDraggable(elmnt) {
        const header = elmnt.querySelector('header');
        const closeBtn = elmnt.querySelector('.close-btn');
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        header.onmousedown = dragMouseDown;

        closeBtn.onclick = () => {
            elmnt.style.display = 'none';
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    })(container);

    // 탭 기능 구현
    (function setupTabs() {
        const tabs = container.querySelectorAll('.tab');
        const tabContents = container.querySelectorAll('.tab-content');

        tabs.forEach(tab => {
            tab.addEventListener('click', () => {
                tabs.forEach(t => t.classList.remove('active'));
                tab.classList.add('active');

                const target = tab.getAttribute('data-tab');
                tabContents.forEach(content => {
                    if(content.id === target){
                        content.classList.add('active');
                    } else {
                        content.classList.remove('active');
                    }
                });
            });
        });
    })();

    // 변수 초기화
    let isRunning = false;
    let isPaused = false;
    let currentPage = 1;
    let results = [];
    let searchQuery = '';
    let searchEngine = '';
    let visitedLinks = new Map(); // 도메인별 방문 횟수 추적
    let logMessages = [];
    let filterPatterns = [];
    let excludeDomains = [];
    let siteFilterPatterns = [];
    let siteFilterKeywords = [];
    let duplicateThreshold = 2; // 중복 허용 횟수
    let retryAttempts = 3; // 재시도 횟수
    let retryInterval = 500; // 재시도 간격 (ms)
    let enableSiteFiltering = true;
    let startTime = null;
    let elapsedInterval = null;
    let crawlChart = null;
    let crawlData = {
        labels: [],  // 도메인 이름
        datasets: [{
            label: '방문 횟수',
            data: [],
            backgroundColor: 'rgba(75, 192, 192, 0.6)',
            borderColor: 'rgba(75, 192, 192, 1)',
            borderWidth: 1
        }]
    };

    // 버튼 및 요소 가져오기
    const startBtn = document.getElementById('startBtn');
    const pauseBtn = document.getElementById('pauseBtn');
    const stopBtn = document.getElementById('stopBtn');
    const resetBtn = document.getElementById('resetBtn');
    const exportBtn = document.getElementById('exportBtn');
    const searchEnginesBtn = document.getElementById('searchEnginesBtn');
    const progressBar = document.getElementById('progressBar');
    const progressText = document.getElementById('progressText');
    const resultsBody = document.getElementById('resultsBody');
    const logContainer = document.getElementById('log');
    const currentPageElem = document.getElementById('currentPage');
    const toggleHTML = document.getElementById('toggleHTML');
    const toggleImages = document.getElementById('toggleImages');
    const toggleAds = document.getElementById('toggleAds');
    const filterInput = document.getElementById('filterInput');
    const excludeDomainsInput = document.getElementById('excludeDomainsInput');
    const siteFilterInput = document.getElementById('siteFilterInput');
    const duplicateThresholdInput = document.getElementById('duplicateThreshold');
    const retryAttemptsInput = document.getElementById('retryAttempts');
    const retryIntervalInput = document.getElementById('retryInterval');
    const enableSiteFilteringCheckbox = document.getElementById('enableSiteFiltering');
    const visitedCountElem = document.getElementById('visitedCount');
    const elapsedTimeElem = document.getElementById('elapsedTime');
    const remainingTimeElem = document.getElementById('remainingTime');
    const crawlChartCtx = document.getElementById('crawlChart').getContext('2d');
    const searchEnginePopup = container.querySelector('.search-engine-popup');
    const htmlDisplayIframe = container.querySelector('.html-display');

    // 이벤트 리스너
    startBtn.addEventListener('click', startCrawling);
    pauseBtn.addEventListener('click', togglePause);
    stopBtn.addEventListener('click', stopCrawling);
    resetBtn.addEventListener('click', resetCrawling);
    exportBtn.addEventListener('click', exportResults);
    searchEnginesBtn.addEventListener('click', toggleSearchEnginesPopup);
    filterInput.addEventListener('input', updateFilterPatterns);
    excludeDomainsInput.addEventListener('input', updateExcludeDomains);
    siteFilterInput.addEventListener('input', updateSiteFilterPatterns);
    duplicateThresholdInput.addEventListener('change', updateDuplicateThreshold);
    retryAttemptsInput.addEventListener('change', updateRetryAttempts);
    retryIntervalInput.addEventListener('change', updateRetryInterval);
    enableSiteFilteringCheckbox.addEventListener('change', updateEnableSiteFiltering);
    searchEnginePopup.addEventListener('click', function(event) {
        if (event.target.classList.contains('search-engine-btn')) {
            window.open(event.target.getAttribute('data-url'), '_blank');
        }
    });

    // 외부 클릭 시 검색 엔진 팝업 닫기
    document.addEventListener('click', function(event) {
        if (!searchEnginePopup.contains(event.target) && event.target !== searchEnginesBtn) {
            searchEnginePopup.style.display = 'none';
        }
    });

    // 페이지 새로 고침 시 크롤링 초기화
    window.addEventListener('beforeunload', () => {
        resetCrawling();
    });

    // 초기화 로드
    loadLogs();
    loadCrawlData();

    // 차트 초기화
    function initializeChart() {
        crawlChart = new Chart(crawlChartCtx, {
            type: 'bar',
            data: crawlData,
            options: {
                responsive: true,
                maintainAspectRatio: false,
                scales: {
                    y: { beginAtZero: true }
                },
                plugins: {
                    legend: {
                        display: false
                    },
                    tooltip: {
                        enabled: true
                    }
                }
            }
        });
    }
    initializeChart();

    // 로깅 함수
    function log(message) {
        const time = new Date().toLocaleTimeString();
        const entry = `[${time}] ${message}`;
        logMessages.push(entry);
        logContainer.innerHTML += `${entry}<br>`;
        logContainer.scrollTop = logContainer.scrollHeight;
        // 저장
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
    }

    function loadLogs() {
        const storedLogs = GM_getValue('crawlerLogs', []);
        if (storedLogs.length > 0) {
            logMessages = JSON.parse(storedLogs);
            logContainer.innerHTML = `<strong>로그:</strong><br>` + logMessages.join('<br>');
            logContainer.scrollTop = logContainer.scrollHeight;
        }
    }

    function updateFilterPatterns() {
        const input = filterInput.value.trim();
        filterPatterns = input ? input.split(',').map(word => {
            word = word.trim();
            if (word.startsWith('/') && word.endsWith('/')) {
                try {
                    return new RegExp(word.slice(1, -1), 'i');
                } catch (e) {
                    log(`⚠️ 유효하지 않은 정규식: ${word}`);
                    return null;
                }
            } else {
                return new RegExp(word, 'i');
            }
        }).filter(regex => regex !== null) : [];
        log(`🛠 필터 패턴 업데이트: [${filterPatterns.map(r => r.toString()).join(', ')}]`);
    }

    function updateExcludeDomains() {
        const input = excludeDomainsInput.value.trim();
        excludeDomains = input ? input.split(',').map(domain => domain.trim().toLowerCase()) : [];
        log(`🚫 제외 도메인 업데이트: [${excludeDomains.join(', ')}]`);
    }

    function updateSiteFilterPatterns() {
        const input = siteFilterInput.value.trim();
        siteFilterKeywords = input ? input.split(',').map(word => word.trim()) : [];
        log(`🛠 사이트 필터링 키워드 업데이트: [${siteFilterKeywords.join(', ')}]`);
    }

    function updateDuplicateThreshold() {
        const value = parseInt(duplicateThresholdInput.value);
        duplicateThreshold = isNaN(value) || value < 1 ? 2 : value;
        log(`🔄 중복 허용 횟수 설정: ${duplicateThreshold}`);
    }

    function updateRetryAttempts() {
        const value = parseInt(retryAttemptsInput.value);
        retryAttempts = isNaN(value) || value < 1 ? 3 : value;
        log(`🔄 재시도 횟수 설정: ${retryAttempts}`);
    }

    function updateRetryInterval() {
        const value = parseInt(retryIntervalInput.value);
        retryInterval = isNaN(value) || value < 100 ? 500 : value;
        log(`🔄 재시도 간격 설정: ${retryInterval}ms`);
    }

    function updateEnableSiteFiltering() {
        enableSiteFiltering = enableSiteFilteringCheckbox.checked;
        log(`🔄 사이트 필터링 기능 ${enableSiteFiltering ? '활성화' : '비활성화'}됨.`);
    }

    function getSearchQueryAndEngine() {
        const url = window.location.href;
        if (url.includes('google.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'google';
        } else if (url.includes('bing.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'bing';
        } else if (url.includes('daum.net/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'daum';
        } else if (url.includes('search.naver.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('query') || '';
            searchEngine = 'naver';
        } else if (url.includes('search.yahoo.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('p') || '';
            searchEngine = 'yahoo';
        } else if (url.includes('duckduckgo.com/')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'duckduckgo';
        } else if (url.includes('ecosia.org/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'ecosia';
        } else {
            searchQuery = '';
            searchEngine = '';
        }
        log(`🔍 검색 엔진: ${searchEngine}, 검색어: "${searchQuery}"`);
    }

    async function startCrawling() {
        if (isRunning) {
            alert('이미 크롤링이 진행 중입니다.');
            return;
        }
        getSearchQueryAndEngine();
        if (!searchQuery) {
            alert('현재 페이지에서 검색어를 찾을 수 없습니다.');
            log('⚠️ 검색어 미입력 또는 인식 실패.');
            return;
        }
        isRunning = true;
        isPaused = false;
        currentPage = 1;
        results = [];
        visitedLinks.clear();
        resultsBody.innerHTML = '';
        visitedCountElem.innerText = '0';
        elapsedTimeElem.innerText = '00:00:00';
        remainingTimeElem.innerText = '00:00:00';
        logMessages = [];
        logContainer.innerHTML = `<strong>로그:</strong><br>`;
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
        log('✅ 크롤링을 시작합니다.');
        updateDuplicateThreshold();
        updateRetryAttempts();
        updateRetryInterval();
        updateFilterPatterns();
        updateExcludeDomains();
        updateSiteFilterPatterns();
        updateEnableSiteFiltering();
        startTime = Date.now();
        elapsedInterval = setInterval(updateElapsedTime, 1000);
        initializeChart();
        await crawlPage();
    }

    function togglePause() {
        if (!isRunning) {
            alert('일시정지/재개할 크롤링이 없습니다.');
            return;
        }
        isPaused = !isPaused;
        if (isPaused) {
            log('⏸️ 크롤링을 일시정지하였습니다.');
            pauseBtn.innerHTML = '<i>▶️</i> 재개';
        } else {
            log('▶️ 크롤링을 재개하였습니다.');
            pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
            crawlPage();
        }
    }

    function stopCrawling() {
        if (!isRunning) {
            alert('중지할 크롤링이 없습니다.');
            return;
        }
        isRunning = false;
        isPaused = false;
        pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
        clearInterval(elapsedInterval);
        updateProgress();
        log('🚫 크롤링을 중지하였습니다.');
        GM_notification({
            text: '크롤링이 중지되었습니다.',
            title: '웹 크롤러 7.6',
            timeout: 3000
        });
    }

    async function crawlPage() {
        if (!isRunning || isPaused) {
            return;
        }

        // 검색 엔진에 따른 URL 구성
        let url = '';
        if (searchEngine === 'google') {
            url = `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&start=${(currentPage-1)*10}`;
        } else if (searchEngine === 'bing') {
            url = `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}&first=${(currentPage-1)*10 +1}`;
        } else if (searchEngine === 'daum') {
            url = `https://search.daum.net/search?q=${encodeURIComponent(searchQuery)}&page=${currentPage}`;
        } else if (searchEngine === 'naver') {
            url = `https://search.naver.com/search.naver?query=${encodeURIComponent(searchQuery)}&start=${(currentPage-1)*10 +1}`;
        } else if (searchEngine === 'yahoo') {
            url = `https://search.yahoo.com/search?p=${encodeURIComponent(searchQuery)}&b=${(currentPage-1)*10 +1}`;
        } else if (searchEngine === 'duckduckgo') {
            url = `https://duckduckgo.com/html/?q=${encodeURIComponent(searchQuery)}&s=${(currentPage-1)*10}`;
        } else if (searchEngine === 'ecosia') {
            url = `https://www.ecosia.org/search?q=${encodeURIComponent(searchQuery)}&page=${currentPage}`;
        } else {
            alert('지원하지 않는 검색 엔진입니다.');
            log('❌ 지원하지 않는 검색 엔진.');
            isRunning = false;
            return;
        }

        log(`📄 페이지 ${currentPage} 크롤링 중: ${url}`);

        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            headers: {
                "User-Agent": navigator.userAgent,
                "Accept": "text/html"
            },
            onload: async function(response) {
                if (response.status !== 200) {
                    log(`❌ 페이지 ${currentPage} 로드 실패: 상태 ${response.status}`);
                    await handleCrawlError(currentPage, retryAttempts);
                    return;
                }

                const parser = new DOMParser();
                const doc = parser.parseFromString(response.responseText, 'text/html');
                let items = [];
                if (searchEngine === 'google') {
                    items = doc.querySelectorAll('div.g');
                } else if (searchEngine === 'bing') {
                    items = doc.querySelectorAll('li.b_algo');
                } else if (searchEngine === 'daum') {
                    items = doc.querySelectorAll('div.wrap_cont');
                } else if (searchEngine === 'naver') {
                    items = doc.querySelectorAll('div.basic1'); // 네이버 최신 선택자 확인 필요
                } else if (searchEngine === 'yahoo') {
                    items = doc.querySelectorAll('div.dd.algo'); // 야후 최신 선택자 확인 필요
                } else if (searchEngine === 'duckduckgo') {
                    items = doc.querySelectorAll('div.result');
                } else if (searchEngine === 'ecosia') {
                    items = doc.querySelectorAll('div.result');
                }

                // 검색 결과가 없으면 크롤링 종료
                if (items.length === 0) {
                    log('🔍 더 이상 크롤링할 페이지가 없습니다. 크롤링을 종료합니다.');
                    isRunning = false;
                    isPaused = false;
                    pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
                    clearInterval(elapsedInterval);
                    updateProgress();
                    GM_notification({
                        text: '크롤링이 완료되었습니다.',
                        title: '웹 크롤러 7.6',
                        timeout: 3000
                    });
                    return;
                }

                log(`📊 페이지 ${currentPage}에서 ${items.length}개 항목 발견.`);

                // 병렬 처리: Promise.all을 이용하여 비동기적으로 처리
                const itemPromises = Array.from(items).map(async (item) => {
                    let title = 'N/A';
                    let link = 'N/A';
                    let description = 'N/A';
                    let image = 'N/A';
                    let htmlLink = 'N/A';
                    let pageLoadTime = 'N/A';

                    // 각 검색 엔진에 따른 데이터 추출
                    if (searchEngine === 'google') {
                        const titleElem = item.querySelector('h3');
                        const linkElem = item.querySelector('a');
                        const descElem = item.querySelector('.IsZvec') || item.querySelector('.VwiC3b');
                        if (titleElem) title = titleElem.innerText;
                        if (linkElem) link = linkElem.href;
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'bing') {
                        const titleElem = item.querySelector('h2 a');
                        const descElem = item.querySelector('p');
                        if (titleElem) {
                            title = titleElem.innerText;
                            link = titleElem.href;
                        }
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'daum') {
                        const titleElem = item.querySelector('a.link_fax');
                        const descElem = item.querySelector('div.cont_inner');
                        if (titleElem) {
                            title = titleElem.innerText.trim();
                            link = titleElem.href;
                        }
                        if (descElem) description = descElem.innerText.trim();

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'naver') {
                        const titleElem = item.querySelector('a.tit');
                        const descElem = item.querySelector('div.desc');
                        if (titleElem) {
                            title = titleElem.innerText;
                            link = titleElem.href;
                        }
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img.thumb');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'yahoo') {
                        const titleElem = item.querySelector('h3');
                        const linkElem = item.querySelector('a');
                        const descElem = item.querySelector('div.compText');
                        if (titleElem) title = titleElem.innerText;
                        if (linkElem) link = linkElem.href;
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'duckduckgo') {
                        const titleElem = item.querySelector('a.result__a');
                        const descElem = item.querySelector('a.result__snippet');
                        if (titleElem) {
                            title = titleElem.innerText;
                            link = titleElem.href;
                        }
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img.result__thumbnail');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    } else if (searchEngine === 'ecosia') {
                        const titleElem = item.querySelector('a.result-title');
                        const descElem = item.querySelector('div.result-description');
                        if (titleElem) {
                            title = titleElem.innerText;
                            link = titleElem.href;
                        }
                        if (descElem) description = descElem.innerText;

                        // 이미지 가져오기 (가능한 경우)
                        const imgElem = item.querySelector('img.result-image');
                        if (imgElem && imgElem.src) {
                            image = `<img src="${imgElem.src}" alt="이미지" style="max-width: 80px; max-height: 80px;">`;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }

                    // 광고 제외 기능 적용
                    if (toggleAds.checked) {
                        const combinedText = `${title} ${description}`.toLowerCase();
                        const isAd = combinedText.includes('advertisement') || combinedText.includes('광고');
                        if (isAd) {
                            log(`🚫 광고 항목 제외: "${title}"`);
                            return null;
                        }
                    }

                    // 필터 단어 적용
                    if (filterPatterns.length > 0) {
                        const combinedText = `${title} ${description}`.toLowerCase();
                        const isFiltered = filterPatterns.some(regex => regex.test(combinedText));
                        if (isFiltered) {
                            log(`❌ 필터 단어 포함 항목 제외: "${title}"`);
                            return null;
                        }
                    }

                    // 사이트 필터링 기능 활성화 시 추가 필터 적용
                    if (enableSiteFiltering && (siteFilterKeywords.length > 0 || siteFilterPatterns.length > 0)) {
                        const combinedText = `${title} ${description}`.toLowerCase();

                        // 키워드 기반 필터링
                        if (siteFilterKeywords.length > 0) {
                            const isKeywordPresent = siteFilterKeywords.some(keyword => combinedText.includes(keyword.toLowerCase()));
                            if (isKeywordPresent) {
                                log(`🚫 사이트 필터 키워드 포함 항목 제외: "${title}"`);
                                return null;
                            }
                        }

                        // 정규식 기반 필터링
                        if (siteFilterPatterns.length > 0) {
                            const isPatternMatch = siteFilterPatterns.some(regex => regex.test(combinedText));
                            if (isPatternMatch) {
                                log(`🚫 사이트 필터 패턴 일치 항목 제외: "${title}"`);
                                return null;
                            }
                        }
                    }

                    // 도메인 추출
                    const domain = extractDomain(link);
                    if (!domain) return null;

                    // 제외 도메인 검사
                    if (excludeDomains.includes(domain.toLowerCase())) {
                        log(`🚫 제외 도메인 항목 제외: "${link}"`);
                        return null;
                    }

                    // 중복 검사 (도메인별 방문 횟수)
                    let visitCount = visitedLinks.get(domain) || 0;
                    if (visitCount >= duplicateThreshold) {
                        log(`🔄 중복 방문 제한: "${domain}"`);
                        return null;
                    }

                    // 방문 횟수 업데이트
                    visitedLinks.set(domain, visitCount + 1);
                    visitedCountElem.innerText = visitedLinks.size.toString();

                    // 페이지 로딩 시간 측정
                    const loadStart = performance.now();
                    try {
                        // mode: 'cors'로 변경하여 실제 응답을 받을 수 있도록 함
                        const fetchResponse = await fetch(link, { mode: 'cors' });
                        if (fetchResponse.ok) {
                            const loadEnd = performance.now();
                            pageLoadTime = Math.round(loadEnd - loadStart);
                        } else {
                            pageLoadTime = '응답 불량';
                        }
                    } catch (err) {
                        pageLoadTime = '계산 불가';
                    }

                    // HTML 옵션
                    if (!toggleHTML.checked) {
                        htmlLink = '비활성화';
                    }

                    // 이미지 옵션
                    if (!toggleImages.checked) {
                        image = '비활성화';
                    }

                    const result = { title, link, description, image, htmlLink, pageLoadTime };
                    results.push(result);

                    // 결과 테이블에 추가
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td>${escapeHTML(title)}</td>
                        <td><a href="${escapeHTML(link)}" target="_blank">${escapeHTML(link)}</a></td>
                        <td>${escapeHTML(description)}</td>
                        <td>${image}</td>
                        <td>${htmlLink}</td>
                        <td>${pageLoadTime}</td>
                    `;
                    resultsBody.appendChild(row);

                    // HTML 콘텐츠 필터링
                    if (enableSiteFiltering && siteFilterKeywords.length > 0) {
                        try {
                            const siteResponse = await fetch(link, { mode: 'cors' });
                            if (siteResponse.ok) {
                                const siteText = await siteResponse.text();
                                const siteHTML = siteText.toLowerCase();
                                const containsKeyword = siteFilterKeywords.some(keyword => siteHTML.includes(keyword.toLowerCase()));
                                if (containsKeyword) {
                                    log(`🚫 HTML 콘텐츠에 필터 키워드 포함: "${title}"`);
                                    row.remove(); // 테이블에서 제거
                                    results.pop(); // 결과 배열에서 제거
                                    return null;
                                }
                            }
                        } catch (err) {
                            log(`⚠️ HTML 콘텐츠 필터링 중 오류 발생: ${err.message}`);
                        }
                    }

                    return result;
                });

                // Promise.all을 통해 모든 항목 처리 완료 대기
                const resultsProcessed = await Promise.all(itemPromises);
                // 필터링으로 인해 제거된 결과는 null이므로 제거
                results = resultsProcessed.filter(item => item !== null);

                // 데이터 시각화 업데이트
                updateChart();

                // 진행률 업데이트
                updateProgress();

                // 다음 페이지로 이동
                currentPage++;
                currentPageElem.innerText = currentPage;

                // 대기 시간 추가하여 서버에 부담 주지 않기
                setTimeout(() => {
                    crawlPage();
                }, isPaused ? 0 : 1500); // 1.5초 대기
            },
            onerror: function() {
                log(`❌ 페이지 ${currentPage} 요청 중 오류 발생.`);
                handleCrawlError(currentPage, retryAttempts);
            }
        });
    }

    async function handleCrawlError(page, retriesLeft) {
        if (retriesLeft > 0 && isRunning) {
            log(`🔄 페이지 ${page} 재시도 (${retriesLeft}회 남음).`);
            setTimeout(() => {
                const url = constructURL(page);
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    headers: {
                        "User-Agent": navigator.userAgent,
                        "Accept": "text/html"
                    },
                    onload: async function(response) {
                        if (response.status === 200) {
                            log(`✅ 페이지 ${page} 재시도 성공.`);
                            await crawlPage();
                        } else {
                            await handleCrawlError(page, retriesLeft - 1);
                        }
                    },
                    onerror: async function() {
                        await handleCrawlError(page, retriesLeft - 1);
                    }
                });
            }, retryInterval);
        } else {
            log(`❌ 페이지 ${page} 로드 실패: 최대 재시도 횟수 초과.`);
            // 크롤링을 중지하지 않고 다음 페이지로 넘어감
            currentPage++;
            currentPageElem.innerText = currentPage;
            setTimeout(() => {
                crawlPage();
            }, 1500);
        }
    }

    function constructURL(page) {
        if (searchEngine === 'google') {
            return `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&start=${(page-1)*10}`;
        } else if (searchEngine === 'bing') {
            return `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}&first=${(page-1)*10 +1}`;
        } else if (searchEngine === 'daum') {
            return `https://search.daum.net/search?q=${encodeURIComponent(searchQuery)}&page=${page}`;
        } else if (searchEngine === 'naver') {
            return `https://search.naver.com/search.naver?query=${encodeURIComponent(searchQuery)}&start=${(page-1)*10 +1}`;
        } else if (searchEngine === 'yahoo') {
            return `https://search.yahoo.com/search?p=${encodeURIComponent(searchQuery)}&b=${(page-1)*10 +1}`;
        } else if (searchEngine === 'duckduckgo') {
            return `https://duckduckgo.com/html/?q=${encodeURIComponent(searchQuery)}&s=${(page-1)*10}`;
        } else if (searchEngine === 'ecosia') {
            return `https://www.ecosia.org/search?q=${encodeURIComponent(searchQuery)}&page=${page}`;
        } else {
            return '';
        }
    }

    function updateProgress() {
        // 무제한이므로 진행률을 페이지 수에 기반하여 표시
        const progressPercent = (currentPage % 100) * 1; // 100페이지마다 100%로 리셋
        progressBar.value = progressPercent > 100 ? 100 : progressPercent;
        progressText.innerText = `페이지 ${currentPage}`;
        if (progressPercent >= 100) {
            progressBar.value = 0;
        }
    }

    function resetCrawling() {
        isRunning = false;
        isPaused = false;
        currentPage = 1;
        results = [];
        visitedLinks.clear();
        resultsBody.innerHTML = '';
        progressBar.value = 0;
        progressText.innerText = '0%';
        currentPageElem.innerText = '0';
        visitedCountElem.innerText = '0';
        elapsedTimeElem.innerText = '00:00:00';
        remainingTimeElem.innerText = '00:00:00';
        logMessages = [];
        logContainer.innerHTML = `<strong>로그:</strong><br>`;
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
        // 차트 초기화
        crawlData.labels = [];
        crawlData.datasets[0].data = [];
        if (crawlChart) {
            crawlChart.update();
        }
        clearInterval(elapsedInterval);
        log('🔄 크롤링을 초기화하였습니다.');
    }

    function exportResults() {
        if (results.length === 0) {
            alert('내보낼 결과가 없습니다.');
            return;
        }
        const format = prompt('내보낼 형식을 선택하세요 (xlsx, csv, json):', 'xlsx');
        if (!format) return;
        if (format.toLowerCase() === 'xlsx') {
            const ws = XLSX.utils.json_to_sheet(results);
            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, ws, "결과");
            XLSX.writeFile(wb, "크롤링_결과.xlsx");
            log('💾 결과를 "크롤링_결과.xlsx" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.xlsx" 파일로 내보냈습니다.',
                title: '웹 크롤러 7.6',
                timeout: 3000
            });
        } else if (format.toLowerCase() === 'csv') {
            const csv = results.map(row => `"${row.title}","${row.link}","${row.description}","${row.image}","${row.htmlLink}","${row.pageLoadTime}"`).join('\n');
            const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '크롤링_결과.csv';
            a.click();
            log('💾 결과를 "크롤링_결과.csv" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.csv" 파일로 내보냈습니다.',
                title: '웹 크롤러 7.6',
                timeout: 3000
            });
        } else if (format.toLowerCase() === 'json') {
            const json = JSON.stringify(results, null, 2);
            const blob = new Blob([json], { type: 'application/json;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '크롤링_결과.json';
            a.click();
            log('💾 결과를 "크롤링_결과.json" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.json" 파일로 내보냈습니다.',
                title: '웹 크롤러 7.6',
                timeout: 3000
            });
        } else {
            alert('지원하지 않는 형식입니다.');
        }
    }

    function escapeHTML(str) {
        if (!str) return '';
        return str.replace(/&/g, "&amp;")
                  .replace(/</g, "&lt;")
                  .replace(/>/g, "&gt;")
                  .replace(/"/g, "&quot;")
                  .replace(/'/g, "&#039;");
    }

    function extractDomain(url) {
        try {
            const urlObj = new URL(url);
            return urlObj.hostname.replace('www.', '');
        } catch (e) {
            return null;
        }
    }

    function updateElapsedTime() {
        if (!startTime) return;
        const now = Date.now();
        const elapsed = Math.floor((now - startTime) / 1000);
        elapsedTimeElem.innerText = formatTime(elapsed);
        const estimatedTotal = currentPage * 1.5; // 예측: 각 페이지 1.5초
        const remaining = Math.max(estimatedTotal - elapsed, 0);
        remainingTimeElem.innerText = formatTime(remaining);
    }

    function formatTime(seconds) {
        const hrs = String(Math.floor(seconds / 3600)).padStart(2, '0');
        const mins = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
        const secs = String(seconds % 60).padStart(2, '0');
        return `${hrs}:${mins}:${secs}`;
    }

    function updateChart() {
        crawlData.labels = Array.from(visitedLinks.keys());
        crawlData.datasets[0].data = Array.from(visitedLinks.values());

        if (crawlChart) {
            crawlChart.update();
        }
        // 저장
        GM_setValue('crawlerData', JSON.stringify(crawlData));
    }

    function loadCrawlData() {
        const storedData = GM_getValue('crawlerData', null);
        if (storedData) {
            const parsedData = JSON.parse(storedData);
            crawlData = parsedData;
            if (crawlChart) {
                crawlChart.data = crawlData;
                crawlChart.update();
            }
        }
    }

    function saveCrawlData() {
        GM_setValue('crawlerData', JSON.stringify(crawlData));
    }

    // 주기적으로 크롤링 데이터를 저장
    setInterval(saveCrawlData, 5000);

    // 검색 엔진 바로 가기 버튼 기능
    function toggleSearchEnginesPopup() {
        if (searchEnginePopup.style.display === 'block') {
            searchEnginePopup.style.display = 'none';
        } else {
            searchEnginePopup.style.display = 'block';
        }
    }

    // HTML 버튼 클릭 및 호버 기능 추가
    container.addEventListener('click', function(event) {
        if (event.target.classList.contains('html-btn') || event.target.parentElement.classList.contains('html-btn')) {
            const btn = event.target.classList.contains('html-btn') ? event.target : event.target.parentElement;
            const url = decodeURIComponent(btn.getAttribute('data-url'));
            showHTMLInUI(url);
        }
    });

    container.addEventListener('mouseover', function(event) {
        const btn = event.target.classList.contains('html-btn') ? event.target : event.target.parentElement;
        if (btn && btn.classList.contains('html-btn')) {
            const url = decodeURIComponent(btn.getAttribute('data-url'));
            showPreviewPopup(btn, url);
        }
    });

    container.addEventListener('mouseout', function(event) {
        if (event.target.classList.contains('html-btn') || event.target.parentElement.classList.contains('html-btn')) {
            const popup = container.querySelector('.preview-popup');
            if (popup) {
                popup.style.display = 'none';
            }
        }
    });

    function showHTMLInUI(url) {
        // UI 내에 iframe을 사용하여 사이트 내용 표시
        if (!htmlDisplayIframe) return;
        htmlDisplayIframe.src = url;
        htmlDisplayIframe.style.display = 'block';
        // 탭을 '결과'로 전환
        switchTab('results');
    }

    function showPreviewPopup(target, url) {
        // 팝업 생성
        let popup = container.querySelector('.preview-popup');
        if (!popup) {
            popup = document.createElement('div');
            popup.className = 'preview-popup';
            container.appendChild(popup);
        }
        popup.style.display = 'block';
        popup.style.left = `${target.getBoundingClientRect().left - container.getBoundingClientRect().left}px`;
        popup.style.top = `${target.getBoundingClientRect().top - container.getBoundingClientRect().top + target.offsetHeight + 5}px`;
        popup.innerHTML = `<iframe src="${url}" style="width:100%; height:100%; border:none;"></iframe>`;
    }

    function switchTab(tabId) {
        const tabs = container.querySelectorAll('.tab');
        const tabContents = container.querySelectorAll('.tab-content');

        tabs.forEach(t => {
            if(t.getAttribute('data-tab') === tabId){
                t.classList.add('active');
            } else {
                t.classList.remove('active');
            }
        });

        tabContents.forEach(content => {
            if(content.id === tabId){
                content.classList.add('active');
            } else {
                content.classList.remove('active');
            }
        });
    }

    // 사이트 필터링 키워드 업데이트
    function updateSiteFilterPatterns() {
        const input = siteFilterInput.value.trim();
        siteFilterKeywords = input ? input.split(',').map(word => word.trim()) : [];
        log(`🛠 사이트 필터링 키워드 업데이트: [${siteFilterKeywords.join(', ')}]`);
    }

    // 주기적으로 크롤링 데이터를 저장
    setInterval(saveCrawlData, 5000);

    // HTML Display iframe 스타일 적용
    GM_addStyle(`
        .html-display {
            width: 100%;
            height: 500px;
            border: 2px solid #4CAF50;
            border-radius: 8px;
            margin-top: 20px;
            background-color: #fff;
            display: none;
        }
    `);

})();        기능들 대폭 개선하셈 
ASSISTANT
확장된 기능을 추가하고 기존 기능을 향상시킨 "종합 웹 크롤러 7.6 Enhanced" 사용자 스크립트를 아래와 같이 제안드립니다. 주요 개선 사항은 다음과 같습니다:

1. **더 많은 검색 엔진 지원**: 추가적인 검색 엔진을 지원하여 크롤링 가능 범위를 확대했습니다.
2. **동적 콘텐츠 로딩 처리**: AJAX로 로드되는 검색 결과를 처리할 수 있도록 개선했습니다.
3. **고급 필터링 옵션**: 콘텐츠 기반 필터링 및 정교한 도메인 제외 기능을 추가했습니다.
4. **성능 최적화**: 비동기 요청과 병렬 처리를 최적화하여 크롤링 속도를 향상시켰습니다.
5. **향상된 UI/UX**: 사용자 인터페이스를 더 직관적이고 반응형으로 개선했습니다.
6. **추가 데이터 분석 기능**: 더 다양한 차트와 데이터 시각화 옵션을 제공했습니다.
7. **세션 데이터 저장 및 복원**: 크롤링 세션을 저장하고 복원할 수 있는 기능을 추가했습니다.
8. **에러 처리 및 알림 강화**: 더 상세한 에러 메시지와 알림 시스템을 구현했습니다.

아래는 이러한 개선 사항이 적용된 업데이트된 스크립트입니다:

```javascript
// ==UserScript==
// @name         종합 웹 크롤러 7.6 Enhanced Plus
// @namespace    http://tampermonkey.net/
// @version      8.0
// @description  고급 기능을 갖춘 웹 크롤러로 검색 결과를 실시간으로 수집하고 표시 (무제한 페이지 지원, 기능 개선 및 추가 기능 포함)
// @author       YourName
// @match        *://www.google.com/search*
// @match        *://www.bing.com/search*
// @match        *://search.daum.net/search*
// @match        *://search.naver.com/search*
// @match        *://search.yahoo.com/search*
// @match        *://duckduckgo.com/*
// @match        *://www.ecosia.org/search*
// @match        *://www.ask.com/*
// @match        *://search.brave.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_notification
// @connect      *
// @require      https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// @require      https://cdn.jsdelivr.net/npm/chart.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js
// ==/UserScript==

(function() {
    'use strict';

    // CSS 스타일 추가 (크롤러 창 대폭 개선)
    GM_addStyle(`
        /* 기본 컨테이너 스타일 */
        #crawler-container {
            position: fixed;
            top: 50px;
            right: 50px;
            background-color: #1e1e1e;
            border: 2px solid #4CAF50;
            padding: 20px;
            z-index: 10000;
            width: 800px;
            max-height: 90vh;
            overflow: hidden;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            border-radius: 10px;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 14px;
            display: flex;
            flex-direction: column;
            transition: all 0.3s ease;
            color: #fff;
        }

        /* 헤더 스타일 */
        #crawler-container header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            background-color: #2d2d30;
            color: #fff;
            padding: 10px 15px;
            border-radius: 8px 8px 0 0;
            cursor: move;
        }

        #crawler-container header .title {
            font-size: 20px;
            font-weight: bold;
        }

        #crawler-container header .close-btn {
            font-size: 24px;
            cursor: pointer;
            transition: color 0.3s;
        }

        #crawler-container header .close-btn:hover {
            color: #ff4d4d;
        }

        /* 탭 스타일 */
        #crawler-container .tabs {
            display: flex;
            border-bottom: 2px solid #4CAF50;
            margin-top: 15px;
        }

        #crawler-container .tab {
            flex: 1;
            padding: 10px;
            text-align: center;
            cursor: pointer;
            background-color: #2d2d30;
            transition: background-color 0.3s, color 0.3s;
            border-right: 1px solid #4CAF50;
        }

        #crawler-container .tab:last-child {
            border-right: none;
        }

        #crawler-container .tab.active {
            background-color: #4CAF50;
            color: #fff;
            font-weight: bold;
            border-bottom: 2px solid #fff;
        }

        /* 탭 콘텐츠 스타일 */
        #crawler-container .tab-content {
            display: none;
            padding: 15px;
            flex-grow: 1;
            overflow-y: auto;
            background-color: #1e1e1e;
        }

        #crawler-container .tab-content.active {
            display: block;
        }

        /* 버튼 스타일 */
        #crawler-container button {
            padding: 8px 12px;
            margin: 6px 4px;
            border: none;
            border-radius: 5px;
            background-color: #4CAF50;
            color: #fff;
            cursor: pointer;
            transition: background-color 0.3s;
            font-size: 14px;
            display: flex;
            align-items: center;
        }

        #crawler-container button:hover {
            background-color: #45a049;
        }

        #crawler-container button i {
            margin-right: 6px;
            font-size: 16px;
        }

        /* Toggle 스위치 스타일 */
        .switch {
          position: relative;
          display: inline-block;
          width: 50px;
          height: 24px;
          margin-left: 10px;
          vertical-align: middle;
        }

        .switch input {
          opacity: 0;
          width: 0;
          height: 0;
        }

        .slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: #ccc;
          transition: .4s;
          border-radius: 24px;
        }

        .slider:before {
          position: absolute;
          content: "";
          height: 18px;
          width: 18px;
          left: 3px;
          bottom: 3px;
          background-color: white;
          transition: .4s;
          border-radius: 50%;
        }

        input:checked + .slider {
          background-color: #4CAF50;
        }

        input:focus + .slider {
          box-shadow: 0 0 1px #4CAF50;
        }

        input:checked + .slider:before {
          transform: translateX(26px);
        }

        /* 기타 섹션 스타일 */
        #crawler-container .options,
        #crawler-container .filters,
        #crawler-container .exclude-domains,
        #crawler-container .advanced-options,
        #crawler-container .site-filters,
        #crawler-container .controls,
        #crawler-container .site-filter-settings,
        #crawler-container .search-settings {
            margin-bottom: 20px;
        }

        /* 입력 필드 스타일 */
        #crawler-container input[type="text"],
        #crawler-container textarea,
        #crawler-container input[type="number"],
        #crawler-container select {
            width: 100%;
            padding: 8px;
            margin-top: 5px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 14px;
            background-color: #2d2d30;
            color: #fff;
        }

        #crawler-container input[type="text"]::placeholder,
        #crawler-container textarea::placeholder {
            color: #aaa;
        }

        /* 테이블 스타일 */
        #crawler-container table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
            font-size: 13px;
            background-color: #1e1e1e;
        }

        #crawler-container th, #crawler-container td {
            border: 1px solid #4CAF50;
            padding: 8px;
            text-align: left;
            vertical-align: middle;
        }

        #crawler-container th {
            background-color: #4CAF50;
            color: #fff;
            position: sticky;
            top: 0;
            z-index: 2;
        }

        /* 로그 섹션 스타일 */
        #crawler-container .log {
            max-height: 150px;
            overflow-y: auto;
            background-color: #2d2d30;
            padding: 10px;
            border: 1px solid #4CAF50;
            border-radius: 5px;
            font-size: 13px;
            white-space: pre-wrap;
        }

        /* 진행률 표시줄과 상태 텍스트 */
        #crawler-container .progress-section {
            display: flex;
            align-items: center;
            margin-top: 10px;
        }

        #crawler-container progress {
            flex: 1;
            height: 20px;
            margin-right: 10px;
        }

        #crawler-container .status {
            font-size: 14px;
            font-weight: bold;
            margin-top: 10px;
        }

        /* 차트 컨테이너 */
        #crawler-container .chart-container {
            position: relative;
            height: 250px;
            margin-top: 20px;
            background-color: #2d2d30;
            padding: 10px;
            border-radius: 5px;
        }

        /* 미리보기 팝업 스타일 */
        .preview-popup {
            position: absolute;
            top: 0;
            left: 0;
            width: 400px;
            height: 300px;
            background-color: #1e1e1e;
            border: 2px solid #4CAF50;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            z-index: 10001;
            display: none;
            border-radius: 8px;
            overflow: hidden;
        }

        /* iframe 스타일 */
        .html-display {
            width: 100%;
            height: 500px;
            border: 2px solid #4CAF50;
            border-radius: 8px;
            margin-top: 20px;
            background-color: #fff;
            display: none;
        }

        /* 검색 엔진 팝업 스타일 */
        .search-engine-popup {
            position: absolute;
            top: 60px;
            right: 20px;
            width: 220px;
            background-color: #2d2d30;
            border: 2px solid #4CAF50;
            box-shadow: 0 8px 30px rgba(0,0,0,0.5);
            z-index: 10002;
            display: none;
            border-radius: 8px;
            padding: 10px;
        }

        .search-engine-popup button {
            width: 100%;
            margin-bottom: 10px;
            background-color: #4CAF50;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .search-engine-popup button:last-child {
            margin-bottom: 0;
        }

        /* 반응형 디자인 */
        @media (max-width: 900px) {
            #crawler-container {
                width: 95%;
                right: 2.5%;
            }

            .preview-popup {
                width: 90%;
                height: 200px;
            }

            .html-display {
                height: 300px;
            }

            #crawler-container .chart-container {
                height: 200px;
            }
        }

        /* 추가된 설정 섹션 스타일 */
        #crawler-container .search-settings label {
            display: block;
            margin-top: 10px;
        }

        #crawler-container .search-settings select {
            margin-top: 5px;
        }
    `);

    // UI 생성 (대폭 개선된 디자인)
    const container = document.createElement('div');
    container.id = 'crawler-container';
    container.innerHTML = `
        <header>
            <span class="title">🔥 웹 크롤러 8.0+</span>
            <span class="close-btn" title="닫기">&times;</span>
        </header>
        <div class="tabs">
            <div class="tab active" data-tab="settings">설정</div>
            <div class="tab" data-tab="results">결과</div>
            <div class="tab" data-tab="logs">로그</div>
            <div class="tab" data-tab="site-filters">사이트 필터</div>
            <div class="tab" data-tab="analysis">분석</div>
        </div>
        <div class="tab-content active" id="settings">
            <!-- 제어 버튼 -->
            <div class="controls">
                <button id="startBtn" title="크롤링 시작"><i>▶️</i> 시작</button>
                <button id="pauseBtn" class="pause-btn" title="크롤링 일시정지/재개"><i>⏸️</i> 일시정지</button>
                <button id="stopBtn" title="크롤링 중지"><i>⏹️</i> 중지</button>
                <button id="resetBtn" title="크롤링 초기화"><i>🔄</i> 초기화</button>
                <button id="exportBtn" class="export-btn" title="결과 내보내기"><i>💾</i> 내보내기</button>
                <button id="searchEnginesBtn" class="search-engines-btn" title="검색 엔진 바로가기"><i>🔍</i> 검색 엔진</button>
            </div>
            <!-- 검색 설정 섹션 -->
            <div class="search-settings">
                <label for="searchType">검색 유형:</label>
                <select id="searchType">
                    <option value="web">웹</option>
                    <option value="images">이미지</option>
                    <option value="news">뉴스</option>
                    <option value="videos">비디오</option>
                </select>
            </div>
            <!-- 옵션 섹션 -->
            <div class="options">
                <label><input type="checkbox" id="toggleHTML" checked> HTML 가져오기</label>
                <label><input type="checkbox" id="toggleImages" checked> 이미지 가져오기</label>
                <label><input type="checkbox" id="toggleAds" checked> 광고 제외</label>
            </div>
            <!-- 사이트 필터링 섹션 -->
            <div class="site-filter-settings">
                <label>사이트 필터링 기능
                    <label class="switch">
                        <input type="checkbox" id="enableSiteFiltering" checked>
                        <span class="slider"></span>
                    </label>
                </label>
            </div>
            <!-- 필터 섹션 -->
            <div class="filters">
                <label for="filterInput">필터 단어 (정규식, 쉼표로 구분):</label>
                <input type="text" id="filterInput" placeholder="예: 기부, 광고, /promo/i">
            </div>
            <!-- 도메인 제외 섹션 -->
            <div class="exclude-domains">
                <label for="excludeDomainsInput">제외할 도메인 (쉼표로 구분):</label>
                <input type="text" id="excludeDomainsInput" placeholder="예: facebook.com, youtube.com">
            </div>
            <!-- 고급 옵션 섹션 -->
            <div class="advanced-options">
                <label for="duplicateThreshold">중복 허용 횟수:</label>
                <input type="number" id="duplicateThreshold" value="2" min="1" style="width: 60px;">
                <label for="retryAttempts">재시도 횟수:</label>
                <input type="number" id="retryAttempts" value="3" min="1" style="width: 60px;">
                <label for="retryInterval">재시도 간격 (ms):</label>
                <input type="number" id="retryInterval" value="500" min="100" style="width: 80px;">
            </div>
            <!-- 진행률 표시 섹션 -->
            <div class="progress-section">
                <progress id="progressBar" value="0" max="100"></progress>
                <span id="progressText">0%</span>
            </div>
            <!-- 상태 정보 섹션 -->
            <div class="status">
                현재 페이지: <span id="currentPage">0</span>
                <br>
                방문된 사이트: <span id="visitedCount">0</span>
                <br>
                경과 시간: <span id="elapsedTime">00:00:00</span>
                <br>
                예상 남은 시간: <span id="remainingTime">00:00:00</span>
            </div>
            <!-- 차트 섹션 -->
            <div class="chart-container">
                <canvas id="crawlChart"></canvas>
            </div>
        </div>
        <div class="tab-content" id="results">
            <div style="margin-top:10px; overflow: auto;">
                <table id="resultsTable">
                    <thead>
                        <tr>
                            <th>사이트 이름</th>
                            <th>주소</th>
                            <th>설명</th>
                            <th>이미지</th>
                            <th>HTML 링크</th>
                            <th>페이지 로딩 시간 (ms)</th>
                        </tr>
                    </thead>
                    <tbody id="resultsBody">
                    </tbody>
                </table>
                <iframe class="html-display" src=""></iframe>
            </div>
        </div>
        <div class="tab-content" id="logs">
            <div class="log" id="log">
                <strong>로그:</strong>
            </div>
        </div>
        <div class="tab-content" id="site-filters">
            <div class="site-filters">
                <label for="siteFilterInput">추가 사이트 필터링 단어 (제목 또는 내용 포함 시 제외, 정규식 지원):</label>
                <input type="text" id="siteFilterInput" placeholder="예: 기부, 광고, /promo/i">
            </div>
        </div>
        <div class="tab-content" id="analysis">
            <div class="analysis-section">
                <h3>데이터 분석</h3>
                <div class="chart-container">
                    <canvas id="distributionChart"></canvas>
                </div>
                <div class="chart-container">
                    <canvas id="responseTimeChart"></canvas>
                </div>
            </div>
        </div>
        <div class="search-engine-popup">
            <button class="search-engine-btn" data-url="https://www.google.com/">Google</button>
            <button class="search-engine-btn" data-url="https://www.bing.com/">Bing</button>
            <button class="search-engine-btn" data-url="https://www.daum.net/">Daum</button>
            <button class="search-engine-btn" data-url="https://www.naver.com/">Naver</button>
            <button class="search-engine-btn" data-url="https://www.yahoo.com/">Yahoo</button>
            <button class="search-engine-btn" data-url="https://duckduckgo.com/">DuckDuckGo</button>
            <button class="search-engine-btn" data-url="https://www.ecosia.org/">Ecosia</button>
            <button class="search-engine-btn" data-url="https://www.ask.com/">Ask</button>
            <button class="search-engine-btn" data-url="https://search.brave.com/">Brave</button>
        </div>
    `;
    document.body.appendChild(container);

    // 드래그 가능하게 설정
    (function makeDraggable(elmnt) {
        const header = elmnt.querySelector('header');
        const closeBtn = elmnt.querySelector('.close-btn');
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        header.onmousedown = dragMouseDown;

        closeBtn.onclick = () => {
            elmnt.style.display = 'none';
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    })(container);

    // 탭 기능 구현
    (function setupTabs() {
        const tabs = container.querySelectorAll('.tab');
        const tabContents = container.querySelectorAll('.tab-content');

        tabs.forEach(tab => {
            tab.addEventListener('click', () => {
                tabs.forEach(t => t.classList.remove('active'));
                tab.classList.add('active');

                const target = tab.getAttribute('data-tab');
                tabContents.forEach(content => {
                    if(content.id === target){
                        content.classList.add('active');
                    } else {
                        content.classList.remove('active');
                    }
                });
            });
        });
    })();

    // 변수 초기화
    let isRunning = false;
    let isPaused = false;
    let currentPage = 1;
    let results = [];
    let searchQuery = '';
    let searchEngine = '';
    let visitedLinks = new Map(); // 도메인별 방문 횟수 추적
    let logMessages = [];
    let filterPatterns = [];
    let excludeDomains = [];
    let siteFilterPatterns = [];
    let siteFilterKeywords = [];
    let duplicateThreshold = 2; // 중복 허용 횟수
    let retryAttempts = 3; // 재시도 횟수
    let retryInterval = 500; // 재시도 간격 (ms)
    let enableSiteFiltering = true;
    let startTime = null;
    let elapsedInterval = null;
    let crawlChart = null;
    let distributionChart = null;
    let responseTimeChart = null;
    let crawlData = {
        labels: [],  // 도메인 이름
        datasets: [{
            label: '방문 횟수',
            data: [],
            backgroundColor: 'rgba(75, 192, 192, 0.6)',
            borderColor: 'rgba(75, 192, 192, 1)',
            borderWidth: 1
        }]
    };

    let distributionData = {
        labels: [],  // 카테고리 레이블
        datasets: [{
            label: '카테고리 분포',
            data: [],
            backgroundColor: 'rgba(153, 102, 255, 0.6)',
            borderColor: 'rgba(153, 102, 255, 1)',
            borderWidth: 1
        }]
    };

    let responseTimeData = {
        labels: [],
        datasets: [{
            label: '페이지 로딩 시간 (ms)',
            data: [],
            backgroundColor: 'rgba(255, 159, 64, 0.6)',
            borderColor: 'rgba(255, 159, 64, 1)',
            borderWidth: 1
        }]
    };

    // 버튼 및 요소 가져오기
    const startBtn = document.getElementById('startBtn');
    const pauseBtn = document.getElementById('pauseBtn');
    const stopBtn = document.getElementById('stopBtn');
    const resetBtn = document.getElementById('resetBtn');
    const exportBtn = document.getElementById('exportBtn');
    const searchEnginesBtn = document.getElementById('searchEnginesBtn');
    const progressBar = document.getElementById('progressBar');
    const progressText = document.getElementById('progressText');
    const resultsBody = document.getElementById('resultsBody');
    const logContainer = document.getElementById('log');
    const currentPageElem = document.getElementById('currentPage');
    const toggleHTML = document.getElementById('toggleHTML');
    const toggleImages = document.getElementById('toggleImages');
    const toggleAds = document.getElementById('toggleAds');
    const filterInput = document.getElementById('filterInput');
    const excludeDomainsInput = document.getElementById('excludeDomainsInput');
    const siteFilterInput = document.getElementById('siteFilterInput');
    const duplicateThresholdInput = document.getElementById('duplicateThreshold');
    const retryAttemptsInput = document.getElementById('retryAttempts');
    const retryIntervalInput = document.getElementById('retryInterval');
    const enableSiteFilteringCheckbox = document.getElementById('enableSiteFiltering');
    const visitedCountElem = document.getElementById('visitedCount');
    const elapsedTimeElem = document.getElementById('elapsedTime');
    const remainingTimeElem = document.getElementById('remainingTime');
    const crawlChartCtx = document.getElementById('crawlChart').getContext('2d');
    const distributionChartCtx = document.getElementById('distributionChart').getContext('2d');
    const responseTimeChartCtx = document.getElementById('responseTimeChart').getContext('2d');
    const searchEnginePopup = container.querySelector('.search-engine-popup');
    const htmlDisplayIframe = container.querySelector('.html-display');
    const searchTypeSelect = document.getElementById('searchType');

    // 이벤트 리스너
    startBtn.addEventListener('click', startCrawling);
    pauseBtn.addEventListener('click', togglePause);
    stopBtn.addEventListener('click', stopCrawling);
    resetBtn.addEventListener('click', resetCrawling);
    exportBtn.addEventListener('click', exportResults);
    searchEnginesBtn.addEventListener('click', toggleSearchEnginesPopup);
    filterInput.addEventListener('input', updateFilterPatterns);
    excludeDomainsInput.addEventListener('input', updateExcludeDomains);
    siteFilterInput.addEventListener('input', updateSiteFilterPatterns);
    duplicateThresholdInput.addEventListener('change', updateDuplicateThreshold);
    retryAttemptsInput.addEventListener('change', updateRetryAttempts);
    retryIntervalInput.addEventListener('change', updateRetryInterval);
    enableSiteFilteringCheckbox.addEventListener('change', updateEnableSiteFiltering);
    searchTypeSelect.addEventListener('change', updateSearchType);
    searchEnginePopup.addEventListener('click', function(event) {
        if (event.target.classList.contains('search-engine-btn')) {
            window.open(event.target.getAttribute('data-url'), '_blank');
        }
    });

    // 외부 클릭 시 검색 엔진 팝업 닫기
    document.addEventListener('click', function(event) {
        if (!searchEnginePopup.contains(event.target) && event.target !== searchEnginesBtn) {
            searchEnginePopup.style.display = 'none';
        }
    });

    // 페이지 새로 고침 시 크롤링 초기화
    window.addEventListener('beforeunload', () => {
        resetCrawling();
    });

    // 초기화 로드
    loadLogs();
    loadCrawlData();
    loadSessionData();

    // 차트 초기화
    function initializeCharts() {
        crawlChart = new Chart(crawlChartCtx, {
            type: 'bar',
            data: crawlData,
            options: {
                responsive: true,
                maintainAspectRatio: false,
                scales: {
                    y: { beginAtZero: true }
                },
                plugins: {
                    legend: {
                        display: false
                    },
                    tooltip: {
                        enabled: true
                    }
                }
            }
        });

        distributionChart = new Chart(distributionChartCtx, {
            type: 'pie',
            data: distributionData,
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'top',
                    },
                    tooltip: {
                        enabled: true
                    }
                }
            }
        });

        responseTimeChart = new Chart(responseTimeChartCtx, {
            type: 'line',
            data: responseTimeData,
            options: {
                responsive: true,
                maintainAspectRatio: false,
                scales: {
                    x: {
                        title: {
                            display: true,
                            text: '페이지 번호'
                        }
                    },
                    y: {
                        beginAtZero: true,
                        title: {
                            display: true,
                            text: '로딩 시간 (ms)'
                        }
                    }
                },
                plugins: {
                    legend: {
                        display: false
                    },
                    tooltip: {
                        enabled: true
                    }
                }
            }
        });
    }
    initializeCharts();

    // 로깅 함수
    function log(message) {
        const time = new Date().toLocaleTimeString();
        const entry = `[${time}] ${message}`;
        logMessages.push(entry);
        logContainer.innerHTML += `${entry}<br>`;
        logContainer.scrollTop = logContainer.scrollHeight;
        // 저장
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
    }

    function loadLogs() {
        const storedLogs = GM_getValue('crawlerLogs', []);
        if (storedLogs.length > 0) {
            logMessages = JSON.parse(storedLogs);
            logContainer.innerHTML = `<strong>로그:</strong><br>` + logMessages.join('<br>');
            logContainer.scrollTop = logContainer.scrollHeight;
        }
    }

    function updateFilterPatterns() {
        const input = filterInput.value.trim();
        filterPatterns = input ? input.split(',').map(word => {
            word = word.trim();
            if (word.startsWith('/') && word.endsWith('/')) {
                try {
                    return new RegExp(word.slice(1, -1), 'i');
                } catch (e) {
                    log(`⚠️ 유효하지 않은 정규식: ${word}`);
                    return null;
                }
            } else {
                return new RegExp(word, 'i');
            }
        }).filter(regex => regex !== null) : [];
        log(`🛠 필터 패턴 업데이트: [${filterPatterns.map(r => r.toString()).join(', ')}]`);
    }

    function updateExcludeDomains() {
        const input = excludeDomainsInput.value.trim();
        excludeDomains = input ? input.split(',').map(domain => domain.trim().toLowerCase()) : [];
        log(`🚫 제외 도메인 업데이트: [${excludeDomains.join(', ')}]`);
    }

    function updateSiteFilterPatterns() {
        const input = siteFilterInput.value.trim();
        siteFilterKeywords = input ? input.split(',').map(word => word.trim()) : [];
        log(`🛠 사이트 필터링 키워드 업데이트: [${siteFilterKeywords.join(', ')}]`);
    }

    function updateDuplicateThreshold() {
        const value = parseInt(duplicateThresholdInput.value);
        duplicateThreshold = isNaN(value) || value < 1 ? 2 : value;
        log(`🔄 중복 허용 횟수 설정: ${duplicateThreshold}`);
    }

    function updateRetryAttempts() {
        const value = parseInt(retryAttemptsInput.value);
        retryAttempts = isNaN(value) || value < 1 ? 3 : value;
        log(`🔄 재시도 횟수 설정: ${retryAttempts}`);
    }

    function updateRetryInterval() {
        const value = parseInt(retryIntervalInput.value);
        retryInterval = isNaN(value) || value < 100 ? 500 : value;
        log(`🔄 재시도 간격 설정: ${retryInterval}ms`);
    }

    function updateEnableSiteFiltering() {
        enableSiteFiltering = enableSiteFilteringCheckbox.checked;
        log(`🔄 사이트 필터링 기능 ${enableSiteFiltering ? '활성화' : '비활성화'}됨.`);
    }

    function updateSearchType() {
        log(`🔄 검색 유형 변경: ${searchTypeSelect.value}`);
    }

    function getSearchQueryAndEngine() {
        const url = window.location.href;
        if (url.includes('google.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'google';
        } else if (url.includes('bing.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'bing';
        } else if (url.includes('daum.net/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'daum';
        } else if (url.includes('search.naver.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('query') || '';
            searchEngine = 'naver';
        } else if (url.includes('search.yahoo.com/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('p') || '';
            searchEngine = 'yahoo';
        } else if (url.includes('duckduckgo.com/')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'duckduckgo';
        } else if (url.includes('ecosia.org/search')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'ecosia';
        } else if (url.includes('ask.com/')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'ask';
        } else if (url.includes('search.brave.com/')) {
            const params = new URLSearchParams(window.location.search);
            searchQuery = params.get('q') || '';
            searchEngine = 'brave';
        } else {
            searchQuery = '';
            searchEngine = '';
        }
        log(`🔍 검색 엔진: ${searchEngine}, 검색어: "${searchQuery}"`);
    }

    async function startCrawling() {
        if (isRunning) {
            alert('이미 크롤링이 진행 중입니다.');
            return;
        }
        getSearchQueryAndEngine();
        if (!searchQuery) {
            alert('현재 페이지에서 검색어를 찾을 수 없습니다.');
            log('⚠️ 검색어 미입력 또는 인식 실패.');
            return;
        }
        isRunning = true;
        isPaused = false;
        currentPage = 1;
        results = [];
        visitedLinks.clear();
        resultsBody.innerHTML = '';
        visitedCountElem.innerText = '0';
        elapsedTimeElem.innerText = '00:00:00';
        remainingTimeElem.innerText = '00:00:00';
        logMessages = [];
        logContainer.innerHTML = `<strong>로그:</strong><br>`;
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
        log('✅ 크롤링을 시작합니다.');
        updateDuplicateThreshold();
        updateRetryAttempts();
        updateRetryInterval();
        updateFilterPatterns();
        updateExcludeDomains();
        updateSiteFilterPatterns();
        updateEnableSiteFiltering();
        startTime = Date.now();
        elapsedInterval = setInterval(updateElapsedTime, 1000);
        initializeCharts();
        await crawlPage();
    }

    function togglePause() {
        if (!isRunning) {
            alert('일시정지/재개할 크롤링이 없습니다.');
            return;
        }
        isPaused = !isPaused;
        if (isPaused) {
            log('⏸️ 크롤링을 일시정지하였습니다.');
            pauseBtn.innerHTML = '<i>▶️</i> 재개';
        } else {
            log('▶️ 크롤링을 재개하였습니다.');
            pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
            crawlPage();
        }
    }

    function stopCrawling() {
        if (!isRunning) {
            alert('중지할 크롤링이 없습니다.');
            return;
        }
        isRunning = false;
        isPaused = false;
        pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
        clearInterval(elapsedInterval);
        updateProgress();
        log('🚫 크롤링을 중지하였습니다.');
        GM_notification({
            text: '크롤링이 중지되었습니다.',
            title: '웹 크롤러 8.0+',
            timeout: 3000
        });
    }

    async function crawlPage() {
        if (!isRunning || isPaused) {
            return;
        }

        // 검색 유형에 따른 URL 구성
        let url = '';
        const searchType = searchTypeSelect.value;
        if (searchEngine === 'google') {
            switch(searchType) {
                case 'images':
                    url = `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&tbm=isch&start=${(currentPage-1)*20}`;
                    break;
                case 'news':
                    url = `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&tbm=nws&start=${(currentPage-1)*20}`;
                    break;
                case 'videos':
                    url = `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&tbm=vid&start=${(currentPage-1)*20}`;
                    break;
                case 'web':
                default:
                    url = `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&start=${(currentPage-1)*10}`;
            }
        } 
        // 유사하게 다른 검색 엔진들도 searchType을 반영하여 URL을 구성
        else if (searchEngine === 'bing') {
            switch(searchType) {
                case 'images':
                    url = `https://www.bing.com/images/search?q=${encodeURIComponent(searchQuery)}&first=${(currentPage-1)*20 +1}`;
                    break;
                case 'news':
                    url = `https://www.bing.com/news/search?q=${encodeURIComponent(searchQuery)}&first=${(currentPage-1)*20 +1}`;
                    break;
                case 'videos':
                    url = `https://www.bing.com/videos/search?q=${encodeURIComponent(searchQuery)}&first=${(currentPage-1)*20 +1}`;
                    break;
                case 'web':
                default:
                    url = `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}&first=${(currentPage-1)*10 +1}`;
            }
        }
        // 다른 검색 엔진들도 비슷하게 구성
        else if (searchEngine === 'ask') {
            url = `https://www.ask.com/web?q=${encodeURIComponent(searchQuery)}&page=${currentPage}`;
        }
        else if (searchEngine === 'brave') {
            url = `https://search.brave.com/search?q=${encodeURIComponent(searchQuery)}&b=${(currentPage-1)*10 +1}`;
        }
        else {
            url = constructURL(currentPage);
        }

        log(`📄 페이지 ${currentPage} 크롤링 중: ${url}`);

        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            headers: {
                "User-Agent": navigator.userAgent,
                "Accept": "text/html"
            },
            onload: async function(response) {
                if (response.status !== 200) {
                    log(`❌ 페이지 ${currentPage} 로드 실패: 상태 ${response.status}`);
                    await handleCrawlError(currentPage, retryAttempts);
                    return;
                }

                const parser = new DOMParser();
                const doc = parser.parseFromString(response.responseText, 'text/html');
                let items = [];
                if (searchEngine === 'google') {
                    if (searchType === 'images') {
                        items = doc.querySelectorAll('div.isv-r');
                    } else if (searchType === 'news') {
                        items = doc.querySelectorAll('div.g');
                    } else if (searchType === 'videos') {
                        items = doc.querySelectorAll('div.g');
                    } else { // web
                        items = doc.querySelectorAll('div.g');
                    }
                } else if (searchEngine === 'bing') {
                    if (searchType === 'images') {
                        items = doc.querySelectorAll('li.imgpt');
                    } else if (searchType === 'news') {
                        items = doc.querySelectorAll('div.news-card');
                    } else if (searchType === 'videos') {
                        items = doc.querySelectorAll('div.video-card');
                    } else { // web
                        items = doc.querySelectorAll('li.b_algo');
                    }
                } else if (searchEngine === 'daum') {
                    items = doc.querySelectorAll('div.wrap_cont');
                } else if (searchEngine === 'naver') {
                    items = doc.querySelectorAll('div.basic1');
                } else if (searchEngine === 'yahoo') {
                    items = doc.querySelectorAll('div.dd.algo');
                } else if (searchEngine === 'duckduckgo') {
                    items = doc.querySelectorAll('div.result');
                } else if (searchEngine === 'ecosia') {
                    items = doc.querySelectorAll('div.result');
                } else if (searchEngine === 'ask') {
                    items = doc.querySelectorAll('div.Result');
                } else if (searchEngine === 'brave') {
                    items = doc.querySelectorAll('div.result');
                }

                // 검색 결과가 없으면 크롤링 종료
                if (items.length === 0) {
                    log('🔍 더 이상 크롤링할 페이지가 없습니다. 크롤링을 종료합니다.');
                    isRunning = false;
                    isPaused = false;
                    pauseBtn.innerHTML = '<i>⏸️</i> 일시정지';
                    clearInterval(elapsedInterval);
                    updateProgress();
                    GM_notification({
                        text: '크롤링이 완료되었습니다.',
                        title: '웹 크롤러 8.0+',
                        timeout: 3000
                    });
                    return;
                }

                log(`📊 페이지 ${currentPage}에서 ${items.length}개 항목 발견.`);

                // 병렬 처리: Promise.all을 이용하여 비동기적으로 처리
                const itemPromises = Array.from(items).map(async (item) => {
                    let title = 'N/A';
                    let link = 'N/A';
                    let description = 'N/A';
                    let image = 'N/A';
                    let htmlLink = 'N/A';
                    let pageLoadTime = 'N/A';

                    // 각 검색 엔진에 따른 데이터 추출
                    if (searchEngine === 'google') {
                        if (searchType === 'images') {
                            const titleElem = item.querySelector('a div[aria-label]');
                            const linkElem = item.querySelector('a');
                            if (titleElem) title = titleElem.getAttribute('aria-label');
                            if (linkElem) link = linkElem.href;
                            // 이미지 직접 링크
                            image = linkElem.querySelector('img') ? linkElem.querySelector('img').src : 'N/A';
                        } else if (searchType === 'news') {
                            const titleElem = item.querySelector('h3');
                            const linkElem = item.querySelector('a');
                            const descElem = item.querySelector('.IsZvec') || item.querySelector('.VwiC3b');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                            if (descElem) description = descElem.innerText;
                        } else if (searchType === 'videos') {
                            const titleElem = item.querySelector('a.video-title');
                            const linkElem = item.querySelector('a');
                            const descElem = item.querySelector('.cVjFH');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                            if (descElem) description = descElem.innerText;
                        } else { // web
                            const titleElem = item.querySelector('h3');
                            const linkElem = item.querySelector('a');
                            const descElem = item.querySelector('.IsZvec') || item.querySelector('.VwiC3b');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                            if (descElem) description = descElem.innerText;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }
                    // Bing, Daum, Naver 등의 검색 엔진도 유사하게 처리
                    else if (searchEngine === 'bing') {
                        if (searchType === 'images') {
                            const titleElem = item.querySelector('a.title');
                            const linkElem = item.querySelector('a');
                            const imgElem = item.querySelector('img');
                            if (titleElem) title = titleElem.alt;
                            if (linkElem) link = linkElem.href;
                            if (imgElem && imgElem.src) {
                                image = imgElem.src;
                            }
                        } else if (searchType === 'news') {
                            const titleElem = item.querySelector('h2 a');
                            const linkElem = item.querySelector('a');
                            const descElem = item.querySelector('.snippet');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                            if (descElem) description = descElem.innerText;
                        } else if (searchType === 'videos') {
                            const titleElem = item.querySelector('h2 a');
                            const linkElem = item.querySelector('a.video-card');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                        } else { // web
                            const titleElem = item.querySelector('h2 a');
                            const linkElem = item.querySelector('a');
                            const descElem = item.querySelector('.b_caption p');
                            if (titleElem) title = titleElem.innerText;
                            if (linkElem) link = linkElem.href;
                            if (descElem) description = descElem.innerText;
                        }

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }
                    // Ask, Brave 등 다른 검색 엔진도 유사하게 데이터 추출
                    else if (searchEngine === 'ask') {
                        const titleElem = item.querySelector('a.result-link');
                        const linkElem = item.querySelector('a');
                        const descElem = item.querySelector('.ResultAbstract');
                        if (titleElem) title = titleElem.innerText;
                        if (linkElem) link = linkElem.href;
                        if (descElem) description = descElem.innerText;

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }
                    else if (searchEngine === 'brave') {
                        const titleElem = item.querySelector('h2 a');
                        const linkElem = item.querySelector('a');
                        const descElem = item.querySelector('.result__snippet');
                        if (titleElem) title = titleElem.innerText;
                        if (linkElem) link = linkElem.href;
                        if (descElem) description = descElem.innerText;

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }
                    else {
                        // 기타 검색 엔진 처리
                        const titleElem = item.querySelector('h3');
                        const linkElem = item.querySelector('a');
                        const descElem = item.querySelector('.description');
                        if (titleElem) title = titleElem.innerText;
                        if (linkElem) link = linkElem.href;
                        if (descElem) description = descElem.innerText;

                        // HTML 보기 링크
                        if (toggleHTML.checked && link !== 'N/A') {
                            htmlLink = `<button class="html-btn" data-url="${encodeURIComponent(link)}"><i>🔗</i> 보기</button>`;
                        }
                    }

                    // 광고 제외 기능 적용
                    if (toggleAds.checked) {
                        const combinedText = `${title} ${description}`.toLowerCase();
                        const isAd = combinedText.includes('advertisement') || combinedText.includes('광고');
                        if (isAd) {
                            log(`🚫 광고 항목 제외: "${title}"`);
                            return null;
                        }
                    }

                    // 필터 단어 적용
                    if (filterPatterns.length > 0) {
                        const combinedText = `${title} ${description}`.toLowerCase();
                        const isFiltered = filterPatterns.some(regex => regex.test(combinedText));
                        if (isFiltered) {
                            log(`❌ 필터 단어 포함 항목 제외: "${title}"`);
                            return null;
                        }
                    }

                    // 사이트 필터링 기능 활성화 시 추가 필터 적용
                    if (enableSiteFiltering && (siteFilterKeywords.length > 0 || siteFilterPatterns.length > 0)) {
                        const combinedText = `${title} ${description}`.toLowerCase();

                        // 키워드 기반 필터링
                        if (siteFilterKeywords.length > 0) {
                            const isKeywordPresent = siteFilterKeywords.some(keyword => combinedText.includes(keyword.toLowerCase()));
                            if (isKeywordPresent) {
                                log(`🚫 사이트 필터 키워드 포함 항목 제외: "${title}"`);
                                return null;
                            }
                        }

                        // 정규식 기반 필터링
                        if (siteFilterPatterns.length > 0) {
                            const isPatternMatch = siteFilterPatterns.some(regex => regex.test(combinedText));
                            if (isPatternMatch) {
                                log(`🚫 사이트 필터 패턴 일치 항목 제외: "${title}"`);
                                return null;
                            }
                        }
                    }

                    // 도메인 추출
                    const domain = extractDomain(link);
                    if (!domain) return null;

                    // 제외 도메인 검사
                    if (excludeDomains.includes(domain.toLowerCase())) {
                        log(`🚫 제외 도메인 항목 제외: "${link}"`);
                        return null;
                    }

                    // 중복 검사 (도메인별 방문 횟수)
                    let visitCount = visitedLinks.get(domain) || 0;
                    if (visitCount >= duplicateThreshold) {
                        log(`🔄 중복 방문 제한: "${domain}"`);
                        return null;
                    }

                    // 방문 횟수 업데이트
                    visitedLinks.set(domain, visitCount + 1);
                    visitedCountElem.innerText = visitedLinks.size.toString();

                    // 페이지 로딩 시간 측정
                    const loadStart = performance.now();
                    try {
                        const fetchResponse = await fetch(link, { mode: 'cors' });
                        if (fetchResponse.ok) {
                            const loadEnd = performance.now();
                            pageLoadTime = Math.round(loadEnd - loadStart);
                        } else {
                            pageLoadTime = '응답 불량';
                        }
                    } catch (err) {
                        pageLoadTime = '계산 불가';
                    }

                    // HTML 옵션
                    if (!toggleHTML.checked) {
                        htmlLink = '비활성화';
                    }

                    // 이미지 옵션
                    if (!toggleImages.checked) {
                        image = '비활성화';
                    }

                    const result = { title, link, description, image, htmlLink, pageLoadTime };
                    results.push(result);

                    // 결과 테이블에 추가
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td>${escapeHTML(title)}</td>
                        <td><a href="${escapeHTML(link)}" target="_blank">${escapeHTML(link)}</a></td>
                        <td>${escapeHTML(description)}</td>
                        <td>${image}</td>
                        <td>${htmlLink}</td>
                        <td>${pageLoadTime}</td>
                    `;
                    resultsBody.appendChild(row);

                    // 응답 시간 차트 업데이트
                    if (pageLoadTime !== 'N/A' && typeof pageLoadTime === 'number') {
                        responseTimeData.labels.push(currentPage);
                        responseTimeData.datasets[0].data.push(pageLoadTime);
                        responseTimeChart.update();
                    }

                    return result;
                });

                // Promise.all을 통해 모든 항목 처리 완료 대기
                const resultsProcessed = await Promise.all(itemPromises);
                // 필터링으로 인해 제거된 결과는 null이므로 제거
                results = resultsProcessed.filter(item => item !== null);

                // 데이터 시각화 업데이트
                updateChart();
                updateDistributionChart();

                // 진행률 업데이트
                updateProgress();

                // 다음 페이지로 이동
                currentPage++;
                currentPageElem.innerText = currentPage;

                // 대기 시간 추가하여 서버에 부담 주지 않기
                setTimeout(() => {
                    crawlPage();
                }, isPaused ? 0 : 1500); // 1.5초 대기
            },
            onerror: function() {
                log(`❌ 페이지 ${currentPage} 요청 중 오류 발생.`);
                handleCrawlError(currentPage, retryAttempts);
            }
        });
    }

    async function handleCrawlError(page, retriesLeft) {
        if (retriesLeft > 0 && isRunning) {
            log(`🔄 페이지 ${page} 재시도 (${retriesLeft}회 남음).`);
            setTimeout(() => {
                const url = constructURL(page);
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    headers: {
                        "User-Agent": navigator.userAgent,
                        "Accept": "text/html"
                    },
                    onload: async function(response) {
                        if (response.status === 200) {
                            log(`✅ 페이지 ${page} 재시도 성공.`);
                            await crawlPage();
                        } else {
                            await handleCrawlError(page, retriesLeft - 1);
                        }
                    },
                    onerror: async function() {
                        await handleCrawlError(page, retriesLeft - 1);
                    }
                });
            }, retryInterval);
        } else {
            log(`❌ 페이지 ${page} 로드 실패: 최대 재시도 횟수 초과.`);
            // 크롤링을 중지하지 않고 다음 페이지로 넘어감
            currentPage++;
            currentPageElem.innerText = currentPage;
            setTimeout(() => {
                crawlPage();
            }, 1500);
        }
    }

    function constructURL(page) {
        if (searchEngine === 'google') {
            return `https://www.google.com/search?q=${encodeURIComponent(searchQuery)}&start=${(page-1)*10}`;
        } else if (searchEngine === 'bing') {
            return `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}&first=${(page-1)*10 +1}`;
        } else if (searchEngine === 'daum') {
            return `https://search.daum.net/search?q=${encodeURIComponent(searchQuery)}&page=${page}`;
        } else if (searchEngine === 'naver') {
            return `https://search.naver.com/search.naver?query=${encodeURIComponent(searchQuery)}&start=${(page-1)*10 +1}`;
        } else if (searchEngine === 'yahoo') {
            return `https://search.yahoo.com/search?p=${encodeURIComponent(searchQuery)}&b=${(page-1)*10 +1}`;
        } else if (searchEngine === 'duckduckgo') {
            return `https://duckduckgo.com/html/?q=${encodeURIComponent(searchQuery)}&s=${(page-1)*10}`;
        } else if (searchEngine === 'ecosia') {
            return `https://www.ecosia.org/search?q=${encodeURIComponent(searchQuery)}&page=${page}`;
        } else if (searchEngine === 'ask') {
            return `https://www.ask.com/web?q=${encodeURIComponent(searchQuery)}&page=${page}`;
        } else if (searchEngine === 'brave') {
            return `https://search.brave.com/search?q=${encodeURIComponent(searchQuery)}&b=${(page-1)*10 +1}`;
        } else {
            return '';
        }
    }

    function updateProgress() {
        // 무제한이므로 진행률을 페이지 수에 기반하여 표시
        const progressPercent = (currentPage % 100) * 1; // 100페이지마다 100%로 리셋
        progressBar.value = progressPercent > 100 ? 100 : progressPercent;
        progressText.innerText = `페이지 ${currentPage}`;
        if (progressPercent >= 100) {
            progressBar.value = 0;
        }
    }

    function resetCrawling() {
        isRunning = false;
        isPaused = false;
        currentPage = 1;
        results = [];
        visitedLinks.clear();
        resultsBody.innerHTML = '';
        progressBar.value = 0;
        progressText.innerText = '0%';
        currentPageElem.innerText = '0';
        visitedCountElem.innerText = '0';
        elapsedTimeElem.innerText = '00:00:00';
        remainingTimeElem.innerText = '00:00:00';
        logMessages = [];
        logContainer.innerHTML = `<strong>로그:</strong><br>`;
        GM_setValue('crawlerLogs', JSON.stringify(logMessages));
        // 차트 초기화
        crawlData.labels = [];
        crawlData.datasets[0].data = [];
        if (crawlChart) {
            crawlChart.update();
        }
        distributionData.labels = [];
        distributionData.datasets[0].data = [];
        if (distributionChart) {
            distributionChart.update();
        }
        responseTimeData.labels = [];
        responseTimeData.datasets[0].data = [];
        if (responseTimeChart) {
            responseTimeChart.update();
        }
        clearInterval(elapsedInterval);
        log('🔄 크롤링을 초기화하였습니다.');
    }

    function exportResults() {
        if (results.length === 0) {
            alert('내보낼 결과가 없습니다.');
            return;
        }
        const format = prompt('내보낼 형식을 선택하세요 (xlsx, csv, json):', 'xlsx');
        if (!format) return;
        if (format.toLowerCase() === 'xlsx') {
            const ws = XLSX.utils.json_to_sheet(results);
            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, ws, "결과");
            XLSX.writeFile(wb, "크롤링_결과.xlsx");
            log('💾 결과를 "크롤링_결과.xlsx" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.xlsx" 파일로 내보냈습니다.',
                title: '웹 크롤러 8.0+',
                timeout: 3000
            });
        } else if (format.toLowerCase() === 'csv') {
            const csv = results.map(row => `"${row.title}","${row.link}","${row.description}","${row.image}","${row.htmlLink}","${row.pageLoadTime}"`).join('\n');
            const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '크롤링_결과.csv';
            a.click();
            log('💾 결과를 "크롤링_결과.csv" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.csv" 파일로 내보냈습니다.',
                title: '웹 크롤러 8.0+',
                timeout: 3000
            });
        } else if (format.toLowerCase() === 'json') {
            const json = JSON.stringify(results, null, 2);
            const blob = new Blob([json], { type: 'application/json;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '크롤링_결과.json';
            a.click();
            log('💾 결과를 "크롤링_결과.json" 파일로 내보냈습니다.');
            GM_notification({
                text: '결과를 "크롤링_결과.json" 파일로 내보냈습니다.',
                title: '웹 크롤러 8.0+',
                timeout: 3000
            });
        } else {
            alert('지원하지 않는 형식입니다.');
        }
    }

    function escapeHTML(str) {
        if (!str) return '';
        return str.replace(/&/g, "&amp;")
                  .replace(/</g, "&lt;")
                  .replace(/>/g, "&gt;")
                  .replace(/"/g, "&quot;")
                  .replace(/'/g, "&#039;");
    }

    function extractDomain(url) {
        try {
            const urlObj = new URL(url);
            return urlObj.hostname.replace('www.', '');
        } catch (e) {
            return null;
        }
    }

    function updateElapsedTime() {
        if (!startTime) return;
        const now = Date.now();
        const elapsed = Math.floor((now - startTime) / 1000);
        elapsedTimeElem.innerText = formatTime(elapsed);
        const estimatedTotal = currentPage * 1.5; // 예측: 각 페이지 1.5초
        const remaining = Math.max(estimatedTotal - elapsed, 0);
        remainingTimeElem.innerText = formatTime(remaining);
    }

    function formatTime(seconds) {
        const hrs = String(Math.floor(seconds / 3600)).padStart(2, '0');
        const mins = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
        const secs = String(seconds % 60).padStart(2, '0');
        return `${hrs}:${mins}:${secs}`;
    }

    function updateChart() {
        crawlData.labels = Array.from(visitedLinks.keys());
        crawlData.datasets[0].data = Array.from(visitedLinks.values());

        if (crawlChart) {
            crawlChart.update();
        }
        // 저장
        GM_setValue('crawlerData', JSON.stringify(crawlData));
    }

    function updateDistributionChart() {
        // 예시: 도메인별 방문 횟수를 기반으로 카테고리 분포 생성
        const categoryMap = {};
        crawlData.labels.forEach((domain, index) => {
            const category = categorizeDomain(domain);
            if (categoryMap[category]) {
                categoryMap[category] += crawlData.datasets[0].data[index];
            } else {
                categoryMap[category] = crawlData.datasets[0].data[index];
            }
        });

        distributionData.labels = Object.keys(categoryMap);
        distributionData.datasets[0].data = Object.values(categoryMap);

        if (distributionChart) {
            distributionChart.update();
        }
        // 저장
        GM_setValue('distributionData', JSON.stringify(distributionData));
    }

    function categorizeDomain(domain) {
        const generalCategories = {
            social: ['facebook.com', 'twitter.com', 'instagram.com', 'linkedin.com'],
            entertainment: ['youtube.com', 'netflix.com', 'hulu.com'],
            news: ['nytimes.com', 'bbc.com', 'cnn.com'],
            eCommerce: ['amazon.com', 'ebay.com', 'shopify.com'],
            technology: ['techcrunch.com', 'wired.com', 'theverge.com']
        };

        for (const [category, domains] of Object.entries(generalCategories)) {
            if (domains.includes(domain)) {
                return category;
            }
        }
        return '기타';
    }

    function loadCrawlData() {
        const storedData = GM_getValue('crawlerData', null);
        if (storedData) {
            const parsedData = JSON.parse(storedData);
            crawlData = parsedData;
            if (crawlChart) {
                crawlChart.data = crawlData;
                crawlChart.update();
            }
        }
    }

    function loadDistributionData() {
        const storedData = GM_getValue('distributionData', null);
        if (storedData) {
            const parsedData = JSON.parse(storedData);
            distributionData = parsedData;
            if (distributionChart) {
                distributionChart.data = distributionData;
                distributionChart.update();
            }
        }
    }

    function loadResponseTimeData() {
        const storedData = GM_getValue('responseTimeData', null);
        if (storedData) {
            const parsedData = JSON.parse(storedData);
            responseTimeData = parsedData;
            if (responseTimeChart) {
                responseTimeChart.data = responseTimeData;
                responseTimeChart.update();
            }
        }
    }

    function saveCrawlData() {
        GM_setValue('crawlerData', JSON.stringify(crawlData));
        GM_setValue('distributionData', JSON.stringify(distributionData));
        GM_setValue('responseTimeData', JSON.stringify(responseTimeData));
    }

    // 주기적으로 크롤링 데이터를 저장
    setInterval(saveCrawlData, 5000);

    function updateChartData() {
        updateChart();
        updateDistributionChart();
    }

    function loadSessionData() {
        loadCrawlData();
        loadDistributionData();
        loadResponseTimeData();
    }

    // 검색 엔진 바로 가기 버튼 기능
    function toggleSearchEnginesPopup() {
        if (searchEnginePopup.style.display === 'block') {
            searchEnginePopup.style.display = 'none';
        } else {
            searchEnginePopup.style.display = 'block';
        }
    }

    // HTML 버튼 클릭 및 호버 기능 추가
    container.addEventListener('click', function(event) {
        if (event.target.classList.contains('html-btn') || event.target.parentElement.classList.contains('html-btn')) {
            const btn = event.target.classList.contains('html-btn') ? event.target : event.target.parentElement;
            const url = decodeURIComponent(btn.getAttribute('data-url'));
            showHTMLInUI(url);
        }
    });

    container.addEventListener('mouseover', function(event) {
        const btn = event.target.classList.contains('html-btn') ? event.target : event.target.parentElement;
        if (btn && btn.classList.contains('html-btn')) {
            const url = decodeURIComponent(btn.getAttribute('data-url'));
            showPreviewPopup(btn, url);
        }
    });

    container.addEventListener('mouseout', function(event) {
        if (event.target.classList.contains('html-btn') || event.target.parentElement.classList.contains('html-btn')) {
            const popup = container.querySelector('.preview-popup');
            if (popup) {
                popup.style.display = 'none';
            }
        }
    });

    function showHTMLInUI(url) {
        // UI 내에 iframe을 사용하여 사이트 내용 표시
        if (!htmlDisplayIframe) return;
        htmlDisplayIframe.src = url;
        htmlDisplayIframe.style.display = 'block';
        // 탭을 '결과'로 전환
        switchTab('results');
    }

    function showPreviewPopup(target, url) {
        // 팝업 생성
        let popup = container.querySelector('.preview-popup');
        if (!popup) {
            popup = document.createElement('div');
            popup.className = 'preview-popup';
            container.appendChild(popup);
        }
        popup.style.display = 'block';
        popup.style.left = `${target.getBoundingClientRect().left - container.getBoundingClientRect().left}px`;
        popup.style.top = `${target.getBoundingClientRect().top - container.getBoundingClientRect().top + target.offsetHeight + 5}px`;
        popup.innerHTML = `<iframe src="${url}" style="width:100%; height:100%; border:none;"></iframe>`;
    }

    function switchTab(tabId) {
        const tabs = container.querySelectorAll('.tab');
        const tabContents = container.querySelectorAll('.tab-content');

        tabs.forEach(t => {
            if(t.getAttribute('data-tab') === tabId){
                t.classList.add('active');
            } else {
                t.classList.remove('active');
            }
        });

        tabContents.forEach(content => {
            if(content.id === tabId){
                content.classList.add('active');
            } else {
                content.classList.remove('active');
            }
        });
    }

    // 사이트 필터링 키워드 업데이트
    function updateSiteFilterPatterns() {
        const input = siteFilterInput.value.trim();
        siteFilterKeywords = input ? input.split(',').map(word => word.trim()) : [];
        log(`🛠 사이트 필터링 키워드 업데이트: [${siteFilterKeywords.join(', ')}]`);
    }

    // 주기적으로 크롤링 데이터를 저장
    setInterval(saveCrawlData, 5000);

    // 데이터 분석 섹션 추가: 카테고리 분포 및 응답 시간 그래프
    function updateAnalysisCharts() {
        updateChartData();
    }

    // 주기적으로 분석 차트를 업데이트
    setInterval(updateAnalysisCharts, 5000);

})();
```

### 주요 개선 사항 상세 설명

1. **더 많은 검색 엔진 지원**:
    - **Ask**와 **Brave** 검색 엔진을 추가하여 더 다양한 검색 결과를 크롤링할 수 있도록 했습니다.
    - `@match` 메타데이터에 새로운 검색 엔진 URL을 추가하고, `getSearchQueryAndEngine` 함수에서 이를 인식하도록 했습니다.

2. **검색 유형 확장**:
    - `searchTypeSelect`를 추가하여 사용자가 웹, 이미지, 뉴스, 비디오 등 다양한 검색 유형을 선택할 수 있게 했습니다.
    - 각 검색 유형에 따라 크롤링할 URL을 동적으로 구성하도록 로직을 추가했습니다.

3. **고급 필터링 옵션**:
    - **사이트 필터링 기능**에 더 정교한 필터링 로직을 추가했습니다. 키워드 기반 및 정규식 기반 필터링을 모두 지원하여 사용자 정의 필터링이 용이해졌습니다.

4. **향상된 UI/UX**:
    - **탭**을 추가하여 설정, 결과, 로그, 사이트 필터뿐만 아니라 데이터 분석 섹션도 제공하여 사용자 경험을 향상시켰습니다.
    - **반응형 디자인**을 강화하여 다양한 화면 크기에서도 원활하게 사용할 수 있도록 했습니다.

5. **추가 데이터 분석 기능**:
    - **카테고리 분포**와 **페이지 로딩 시간**을 시각화할 수 있는 추가적인 차트를 도입했습니다.
    - 각 도메인을 일반적인 카테고리(예: 소셜, 엔터테인먼트, 뉴스 등)로 분류하여 분포 정보를 제공합니다.

6. **세션 데이터 저장 및 복원**:
    - 크롤링 중간에 브라우저를 새로 고침해도 현재 세션 데이터를 저장하고 복원할 수 있도록 `loadSessionData` 함수를 추가했습니다.

7. **에러 처리 및 알림 강화**:
    - 에러 발생 시 더 상세한 로그 메세지를 제공하고, 사용자가 쉽게 이해할 수 있도록 개선했습니다.
    - 크롤링이 완료되거나 중지될 때 데스크탑 알림을 통해 사용자에게 상태를 알려줍니다.

8. **성능 최적화**:
    - 비동기 요청을 효율적으로 처리하여 크롤링 속도를 향상시켰습니다.
    - 데이터 시각화 업데이트 로직을 최적화하여 브라우저 성능에 미치는 영향을 최소화했습니다.

### 추가 권장 사항

1. **로봇 배제 표준(robots.txt) 준수**:
    - 웹 크롤링 시 해당 사이트의 `robots.txt` 파일을 확인하여 크롤링 정책을 준수하는 것이 중요합니다. 이는 웹 서버에 과도한 부하를 방지하고 법적 문제를 피하는 데 도움이 됩니다.

2. **CAPTCHA 처리**:
    - 일부 검색 엔진은 자동화된 크롤링을 차단하기 위해 CAPTCHA를 사용합니다. 이러한 경우 사용자에게 적절한 안내를 제공하거나 CAPTCHA를 우회하는 방법을 고려할 수 있습니다. 다만, 이는 서비스 약관 위반이 될 수 있으므로 신중히 접근해야 합니다.

3. **프록시 및 사용자 에이전트 설정**:
    - 크롤링 속도를 제어하거나 IP 차단을 피하기 위해 프록시 서버를 사용하는 방법도 고려할 수 있습니다. 또한, 다양한 사용자 에이전트를 사용하여 요청을 수행하면 더 자연스러운 크롤링이 가능합니다.

4. **데이터 저장 및 관리**:
    - 크롤링한 데이터를 효과적으로 관리하기 위해 로컬 스토리지 외에도 외부 데이터베이스나 클라우드 스토리지를 연동할 수 있습니다.

5. **UI 개선**:
    - 현재의 UI는 기본적인 기능을 제공하지만, 사용자 친화적인 디자인과 추가적인 기능(예: 테마 변경, 사용자 정의 필드 등)을 도입하면 더욱 향상된 사용자 경험을 제공할 수 있습니다.

이 업데이트된 스크립트는 기존의 기능을 유지하면서 더 많은 검색 엔진 지원, 고급 필터링, 향상된 UI/UX, 추가적인 데이터 분석 기능 등을 제공하여 전반적인 크롤링 경험을 크게 향상시킵니다. 사용자의 특정 요구사항에 따라 추가적인 기능을 더할 수도 있습니다. 필요에 따라 코드를 수정하거나 새로운 기능을 추가해보세요.

turns-00051.parquet:24780

2f0fd5672ff60513b2622a14
turn 1/1gpt-4o-2024-08-06VietnameseBrazil1712 words
degenerate_repetitionAbsentFinal dense release
USER
Bạn sẽ nhận được một đoạn ngữ cảnh mô tả một sự kiện hoặc khái niệm cụ thể. Dựa trên ngữ cảnh, hãy tạo ra 3 cặp câu hỏi và câu trả lời đi kèm. Hãy đảm bảo rằng câu trả lời có sự giải thích từng bước hoặc mô tả chi tiết (Chain of Thought) để người đọc hiểu rõ hơn về nội dung câu trả lời.
    Yêu cầu: Tạo 3 cặp câu hỏi và câu trả lời. Hãy lưu ý cung cấp câu trả lời theo từng bước suy luận, hoặc đưa ra các yếu tố giải thích rõ ràng liên quan đến câu trả lời (Chain of Thought). Bước suy luận sẽ lấy thông tin trực tiếp từ ngữ cảnh, thông tin được lấy từ ngữ cảnh sẽ được bỏ vào 2 tag đặc biệt ###begin_context### và ###end_context###. Câu trả lời sẽ ở dạng ngắn gọn, súc tích.

    Câu hỏi được bỏ vào tag ###Câu hỏi:
    Suy luận được bỏ vào tag ###Suy luận:
    Câu trả lời được bỏ vào tag đặc biệt ###Câu trả lời:
    Suy luận bắt buộc phải trích xuất thông tin từ ngữ cảnh và dùng ###begin_context### và ###end_context### để đánh dấu thông tin được trích xuất.

    Nếu ngữ cảnh không có ý nghĩa, bạn hãy output "Ngữ cảnh không giá trị".
    Trả lời bằng tiếng Việt.
    Trả cho tôi output dưới dạng json để có thể trích xuất một cách dễ dàng.

    Ví dụ:
    ###Ngữ cảnh: Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách. Với trên 145 tổ chức thành viên và 65.000 thành viên cá nhân, ISOC bao gồm những con người cụ thể trong cộng đồng Internet. Mọi chi tiết có thể tìm thấy tại website của ISOC.
Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ. Số hội viên của nó bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân. Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.
Nhiệm vụ và mục đích hoạt động.
Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.
    ###Đầu ra: json```{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Internet Society (ISOC) là tổ chức gì và mục tiêu chính của nó là gì?",
            "###Suy luận:": "###begin_context###Internet Society hay ISOC là một tổ chức quốc tế hoạt động phi lợi nhuận, phi chính phủ và bao gồm các thành viên có trình độ chuyên ngành. Tổ chức này chú trọng đến: tiêu chuẩn, giáo dục và các vấn đề về chính sách.###end_context### chỉ ra rằng Internet Society là một tổ chức quốc tế, phi lợi nhuận và phi chính phủ, tập trung vào tiêu chuẩn, giáo dục và các vấn đề chính sách. ###begin_context###Nhiệm vụ và mục đích hoạt động: Bảo đảm, cổ vũ cho sự phát triển, mở rộng và sử dụng Internet được thuận lợi nhất cho mọi người trên toàn thế giới.###end_context### chỉ ra rằng mục tiêu chính của ISOC là bảo đảm và cổ vũ cho sự phát triển, mở rộng và sử dụng Internet thuận lợi nhất cho mọi người trên toàn thế giới.",
            "###Câu trả lời:": "Internet Society (ISOC) là một tổ chức quốc tế phi lợi nhuận và phi chính phủ, nhằm bảo đảm và thúc đẩy sự phát triển, mở rộng và sử dụng Internet một cách thuận lợi cho mọi người trên toàn thế giới."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có quy mô thành viên như thế nào?",
            "###Suy luận:": "###begin_context###Internet Society bao gồm hơn 145 tổ chức thành viên và hơn 65.000 cá nhân.###end_context### chỉ ra rằng ISOC có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân. ###begin_context###Thành viên còn có thể tự lập một chi nhánh của tổ chức tùy theo vị trí hoặc sở thích. Hiện nay tổ chức có tới 90 chi nhánh trên toàn thế giới.###end_context### chỉ ra rằng các thành viên còn có thể lập chi nhánh của tổ chức tùy theo vị trí hoặc sở thích, với tổng cộng 90 chi nhánh trên toàn cầu.",
            "###Câu trả lời:": "Internet Society (ISOC) có hơn 145 tổ chức thành viên và hơn 65.000 thành viên cá nhân, cùng với 90 chi nhánh trên toàn cầu được thành lập bởi các thành viên theo vị trí hoặc sở thích."
        },
        {
            "###Câu hỏi:": "Internet Society (ISOC) có trụ sở chính ở đâu?",
            "###Suy luận:": "###begin_context###Internet Society nằm ở gần thủ đô Washington, DC, Hoa Kỳ và Geneva, Thụy Sĩ.###end_context### chỉ ra ra rằng ISOC có trụ sở tại hai địa điểm gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ).",
            "###Câu trả lời:": "Internet Society (ISOC) có trụ sở chính gần thủ đô Washington, DC (Hoa Kỳ) và Geneva (Thụy Sĩ)."
        }
    ]
}
```


    Đến lượt bạn:
    ###Ngữ cảnh: Đức Mẹ La Vang thường được biểu tượng bằng một phụ nữ mặc [[áo dài]] Việt Nam bế con cũng mặc trang phục truyền thống Việt Nam.
Nhà thờ La Vang.
[[Tập tin:Thánh đường La Vang.JPG|nhỏ|200px|phải|Chỉ còn lại di tích tháp chuông từ Thánh đường La Vang cũ]]
Lịch sử Đức Mẹ hiện ra và lập nhà thờ không rõ ràng vì đã quá lâu và không được biên chép từ thời đó, hầu hết chỉ có lời truyền khẩu và nhiều giả thuyết khác nhau. Có giả thuyết là nhà thờ La Vang vốn được xây trên nền của một mái chùa [[Phật giáo]] hoặc là một miếu thờ Bà (có thể là [[Phật Bà Quan Âm]] hoặc [[bà chúa Liễu Hạnh]]) cho người đi rừng , nguyên là một mái nhà tranh dưới gốc cây đa và rào sơ bốn mặt, sau biến cố Mẹ Maria hiện ra năm 1798 được nhường cho giáo dân để xây một nơi tôn kính Mẹ Maria. Nhưng cũng có ý kiến khác cho rằng La Vang trước đó chỉ là một vùng hoang vắng, vùng rừng núi hẻo lánh.
Theo Giám mục [[Giuse Đa Minh Hồ Ngọc Cẩn|Hồ Ngọc Cẩn]] kể lại lời truyền khẩu là năm 1885 nhà thờ bị đốt, và một nhóm giáo dân La Vang dựng lại nhà thờ Đức Mẹ trên nền cũ. Linh mục quản hạt Quảng Trị Patinier Kinh trong báo cáo năm 1894 có viết: "Năm 1885 ngôi nhà thờ ở đây cũng như những nhà thờ khác trong hạt, không thoát khỏi thảm họa... Khi hòa bình vừa vãn hồi, con đã cấp tốc dựng lại ngôi nhà thờ nhỏ bé, tạm bợ để chờ nguồn kinh phí cũng như để chờ cho tình hình bớt nhiễu nhương". Năm 1886 (có bản ghi là năm 1894), Giám mục Caspar (Lộc) cho xây lại nơi đây đền thờ bằng [[ngói]], vì xây trên một vùng núi vận chuyển vật liệu khó khăn nên 15 năm mới hoàn thành. Năm 1901, đại hội La Vang đầu tiên được tổ chức vào ngày 8 tháng 8 để mừng khánh thành nhà thờ.
Năm 1924, nhận thấy ngôi nhà thờ ngói quá chật hẹp, lại đã xuống cấp cho nên một đền thánh La Vang theo đồ án của kiến trúc sư Carpentier được dựng lên thay thế và được khánh thành vào ngày 20 tháng 8 năm [[1928]], nhân dịp Đại hội La Vang 9. Thánh đường này được trùng tu năm 1959.
    ###Đầu ra:
    
ASSISTANT
```json
{
    "QA_pairs": [
        {
            "###Câu hỏi:": "Đức Mẹ La Vang được biểu tượng bằng hình ảnh gì?",
            "###Suy luận:": "###begin_context###Đức Mẹ La Vang thường được biểu tượng bằng một phụ nữ mặc [[áo dài]] Việt Nam bế con cũng mặc trang phục truyền thống Việt Nam.###end_context### chỉ ra rằng biểu tượng của Đức Mẹ La Vang là một phụ nữ mặc áo dài Việt Nam bế con, cả hai đều mặc trang phục truyền thống Việt Nam.",
            "###Câu trả lời:": "Đức Mẹ La Vang được biểu tượng bằng hình ảnh một phụ nữ mặc áo dài Việt Nam bế con, đều mặc trang phục truyền thống."
        },
        {
            "###Câu hỏi:": "Nguồn gốc của nhà thờ La Vang có phải là một nơi thờ Phật giáo?",
            "###Suy luận:": "###begin_context###Lịch sử Đức Mẹ hiện ra và lập nhà thờ không rõ ràng vì đã quá lâu và không được biên chép từ thời đó, hầu hết chỉ có lời truyền khẩu và nhiều giả thuyết khác nhau. Có giả thuyết là nhà thờ La Vang vốn được xây trên nền của một mái chùa [[Phật giáo]] hoặc là một miếu thờ Bà...###end_context### chỉ ra rằng có giả thuyết cho rằng nhà thờ La Vang được xây trên nền chùa Phật giáo hoặc miếu thờ Bà, tuy nhiên không có thông tin chính xác để xác nhận điều này.",
            "###Câu trả lời:": "Có giả thuyết cho rằng nhà thờ La Vang được xây trên nền chùa Phật giáo hoặc miếu thờ Bà, nhưng không có thông tin chính xác để xác nhận điều này."
        },
        {
            "###Câu hỏi:": "Nhà thờ La Vang đã được xây dựng lại khi nào và bởi ai?",
            "###Suy luận:": "###begin_context###Năm 1885 nhà thờ bị đốt, và một nhóm giáo dân La Vang dựng lại nhà thờ Đức Mẹ trên nền cũ... Năm 1886 (có bản ghi là năm 1894), Giám mục Caspar (Lộc) cho xây lại nơi đây đền thờ bằng [[ngói]]...###end_context### chỉ ra rằng sau khi nhà thờ La Vang bị đốt năm 1885, nó được dựng lại bởi một nhóm giáo dân và sau đó được Giám mục Caspar (Lộc) xây lại thành đền thờ bằng ngói năm 1886 (có nguồn ghi 1894).",
            "###Câu trả lời:": "Nhà thờ La Vang bị đốt năm 1885, sau đó được dựng lại bởi một nhóm giáo dân và tiếp tục được Giám mục Caspar (Lộc) xây lại thành đền thờ bằng ngói vào năm 1886 (hoặc 1894 theo một số nguồn)."
        }
    ]
}
```