diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..080c96b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,42 @@ +name: "๐Ÿž Bug" +description: "๋ฒ„๊ทธ ์ œ๋ณด" +labels: "bug" +body: + - type: markdown + attributes: + value: | + ## ๐Ÿ› ๋ฒ„๊ทธ ์ œ๋ณด + - ๋ฐœ๊ฒฌํ•œ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ฃผ์„ธ์š”. + - ๊ด€๋ จ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฒจ๋ถ€ํ•˜๋ฉด ๋”์šฑ ๋น ๋ฅธ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. + + - type: textarea + attributes: + label: "๐Ÿ“„ ์„ค๋ช…" + description: "๋ฐœ๊ฒฌํ•œ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”." + placeholder: "์–ด๋””์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”." + validations: + required: true + + - type: textarea + attributes: + label: "๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท / ๋กœ๊ทธ" + description: "๊ด€๋ จ๋œ ์Šคํฌ๋ฆฐ์ƒท ๋˜๋Š” ์ฝ˜์†” ์—๋Ÿฌ ๋กœ๊ทธ๋ฅผ ์ฒจ๋ถ€ํ•ด์ฃผ์„ธ์š”." + placeholder: "์Šคํฌ๋ฆฐ์ƒท ๋˜๋Š” ์ฝ˜์†” ์—๋Ÿฌ" + + - type: textarea + attributes: + label: "๐Ÿ’ป ํ™˜๊ฒฝ ์ •๋ณด" + description: "๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ ํ™˜๊ฒฝ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”." + placeholder: "์‚ฌ์šฉํ•œ ์„œ๋ฒ„๋‚˜ ๊ธฐ๊ธฐ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”." + + - type: textarea + attributes: + label: "๐Ÿ“Ž ์ฐธ๊ณ " + description: "์ฐธ๊ณ ํ•  ์ž๋ฃŒ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋งํฌ ๋˜๋Š” ์ž๋ฃŒ๋ฅผ ์ฒจ๋ถ€ํ•ด์ฃผ์„ธ์š”." + placeholder: "https://example.com" + + - type: markdown + attributes: + value: | + --- + ์ด์ƒ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..fb192c1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,39 @@ +name: "๐Ÿš€ Feature" +description: "์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ œ์•ˆ ๋˜๋Š” ์š”์ฒญ" +labels: ["feature", "enhancement"] +body: + - type: markdown + attributes: + value: | + ## ๐Ÿ“Œ ๊ธฐ๋Šฅ ์š”์ฒญ + - ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ œ์•ˆํ•˜๋Š” ๊ฒฝ์šฐ ์•„๋ž˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”. + + - type: textarea + attributes: + label: "๐Ÿ“„ ์„ค๋ช…" + description: "๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”." + placeholder: "์„ค๋ช…์—๋Š” ๊ธฐ๋Šฅ์˜ ํ•„์š”์„ฑ, ๋ชฉ์ , ์˜ˆ์ƒ ํšจ๊ณผ ๋“ฑ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”." + validations: + required: true + + - type: textarea + attributes: + label: "โœ… ์ž‘์—…" + description: "๊ตฌ์ฒด์ ์ธ ์ž‘์—…์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”." + placeholder: | + - [ ] ๊ตฌ์ฒด์ ์ธ ์ž‘์—… ๋‚ด์šฉ + value: "- [ ] " + validations: + required: true + + - type: textarea + attributes: + label: "๐Ÿ“Ž ์ฐธ๊ณ " + description: "์ฐธ๊ณ ํ•  ์ž๋ฃŒ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋งํฌ ๋˜๋Š” ์ž๋ฃŒ๋ฅผ ์ฒจ๋ถ€ํ•ด์ฃผ์„ธ์š”." + placeholder: "https://example.com" + + - type: markdown + attributes: + value: | + --- + ์ด์ƒ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8266455 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +## ๐Ÿ’ฝ ์š”์•ฝ + + +## ๐Ÿ’ป ์ž‘์—… ๋‚ด์šฉ + + +## ๐Ÿ“Ž Issue ๋ฒˆํ˜ธ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f847a20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# models +models/final_outputs +models/product_summarization/config/config_v1.yaml +models/product_summarization/data/* + +# demo +.env +back/env.sh + +# files +*.csv +*.npy +__pycache__ + +# api file +config_api_key.yaml + +# macOS +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..64942b8 --- /dev/null +++ b/README.md @@ -0,0 +1,177 @@ +
+ +# [Lv. 4] ๊ธฐ์—…์—ฐ๊ณ„ํ•ด์ปคํ†ค - ๋„ค์ด๋ฒ„ ํด๋ผ์šฐ๋“œ + +## ๐Ÿ›๏ธ Foodly (์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์‹๋ฃŒํ’ˆ ์‡ผํ•‘ ์„œ๋น„์Šค) + +image + + +
+ +## ๐Ÿƒ ํ”„๋กœ์ ํŠธ ์„ค๋ช… + +### ๐Ÿ–ฅ๏ธ ํ”„๋กœ์ ํŠธ ๊ฐœ์š” + +
+ +
+ +| ํŠน์ง•ใ€€ใ€€ใ€€ใ€€| ์„ค๋ช… | +|:-------:| --- | +| ์ฃผ์ œ | ์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์˜จ๋ผ์ธ ์‹๋ฃŒํ’ˆ ์‡ผํ•‘ ์ง€์› ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. | +| ๋ฌธ์ œ ์ •์˜ | ์˜จ๋ผ์ธ ์‡ผํ•‘์€ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํŽธ๋ฆฌํ•œ ๊ณผ์ •์ด์ง€๋งŒ, ์‹œ๊ฐ์žฅ์• ์ธ์—๊ฒŒ๋Š” ํ™”๋ฉด์˜ ๋ชจ๋“  ๋‚ด์šฉ์„ ์Œ์„ฑ์œผ๋กœ ๋“ฃ๊ณ  ์ •๋ณด๋ฅผ ์ฐพ๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ, ์ƒํ’ˆ์˜ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด์™€ ์•Œ๋ ˆ๋ฅด๊ธฐ ์ •๋ณด ๋“ฑ ์ด๋ฏธ์ง€๋กœ ์ œ๊ณต๋˜๋Š” ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์—์„œ ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. | +| ๊ธฐ๋Šฅ | - ์ƒํ’ˆ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€(์ธ๋„ค์ผ)๋ฅผ ํ…์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ „๋‹ฌ
- ์ƒํ’ˆ์˜ ํฌ๊ธฐ ์ •๋ณด, ๋ณด๊ด€๋ฒ•, ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ๋“ฑ์˜ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์ง๊ด€์ ์ธ ํ…์ŠคํŠธ๋กœ ์ œ๊ณต
- ๋ฆฌ๋ทฐ ๊ธยท๋ถ€์ • ์˜๊ฒฌ ์š”์•ฝ, ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ์ถ”์ฒœ ์‹œ์Šคํ…œ ๊ฐœ๋ฐœ | +| ๊ฒฐ๊ณผ๋ฌผ | [WrapUp Report](https://github.com/boostcampaitech7/level4-nlp-finalproject-hackathon-nlp-05-lv3/blob/main/doc/Foodly_Wrap-Up_Report.pdf), [Presentation Material](https://github.com/boostcampaitech7/level4-nlp-finalproject-hackathon-nlp-05-lv3/blob/main/doc/Foodly_Presentation.pdf) | + +
+ +### ๐Ÿ’ก ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ +image + + +### โœ… ์‹œ๊ฐ์žฅ์• ์ธ 7๋ถ„์˜ ํ‘ธ๋“œ๋ฆฌ ์‚ฌ์šฉ์„ฑ ํ‰๊ฐ€ +แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2025-02-18 แ„‹แ…ฉแ„’แ…ฎ 9 01 07 + + +
+ +
+ +## ๐ŸŸ "๋‚˜์•ผ, ์ž, ์—ฐ์–ด"ํŒ€ ๋ฉค๋ฒ„ ์†Œ๊ฐœ +| ๊ณฝํฌ์ค€  [](https://github.com/gwaksital) | ๊น€์ •์€  [](https://github.com/wjddms4299) | ๊น€์ง„์žฌ  [](https://github.com/jin-jae) | ์˜ค์ˆ˜ํ˜„  [](https://github.com/ocean010315) | ์œค์„ ์›…  [](https://github.com/ssunbear) | ์ •๋ฏผ์ง€  [](https://github.com/minjijeong98) +|:-:|:-:|:-:|:-:|:-:|:-:| +| ![๊ณฝํฌ์ค€](https://avatars.githubusercontent.com/u/80732503) | ![๊น€์ •์€](https://avatars.githubusercontent.com/u/121777522) | ![๊น€์ง„์žฌ](https://avatars.githubusercontent.com/u/97018331) | ![์˜ค์ˆ˜ํ˜„](https://avatars.githubusercontent.com/u/91974779) | ![์œค์„ ์›…](https://avatars.githubusercontent.com/u/117508164) | ![์ •๋ฏผ์ง€](https://avatars.githubusercontent.com/u/162319450) | + +
+ +## ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป ์—ญํ•  ๋ถ„๋‹ด +| ํŒ€์›ใ€€ใ€€| ์—ญํ•  | +|:--------:| -------------- | +| ๊ณฝํฌ์ค€ | ๋ฆฌ๋ทฐ ์š”์•ฝ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ - ASTE(ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„, ๋ฐ์ดํ„ฐ ์—”์ง€๋‹ˆ์–ด๋ง, Metric ์„ ์ •), Clustering์„ ํ†ตํ•œ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ํฌํ•จ ๊ฒ€์ƒ‰๊ณผ ๋ฆฌ๋ทฐ ์š”์•ฝ | +| ๊น€์ •์€ | ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ์ถ”์ถœ - YOLO11 SFT, CLOVA OCR output ํ›„์ฒ˜๋ฆฌ, Rule-based ๋ฐฉ์‹ ์ ์šฉ ์‹คํ—˜, HCX Fine-Tuning, ํ‰๊ฐ€ Metric ์„ ์ • | +| ๊น€์ง„์žฌ | ํฌ๊ธฐ ์ •๋ณด ๋ฌ˜์‚ฌ, ๋ฆฌ๋ทฐ ์š”์•ฝ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ, ์•ฑ ๊ฐœ๋ฐœ - ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ง•, YOLO11 SFT, Rule-based ํ›„์ฒ˜๋ฆฌ, ASTE(HCX/DeepSeek Prompt Engineering, DeepSeek SFT), React Native, React (Chrome Extension) Spring Framework ๊ฐœ๋ฐœ | +| ์˜ค์ˆ˜ํ˜„ | ๋ฆฌ๋ทฐ ์š”์•ฝ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ - ASTE(HCX/DeepSeek Prompt Engineering, DeepSeek SFT), Clustering์„ ํ†ตํ•œ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ํฌํ•จ ๊ฒ€์ƒ‰๊ณผ ๋ฆฌ๋ทฐ ์š”์•ฝ | +| ์œค์„ ์›… | ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ์„ค๋ช… ์ƒ์„ฑ - Janus Pro Fine-Tuning, HCX ํ›„์ฒ˜๋ฆฌ(์š”์•ฝ, ๋ฒˆ์—ญ, Hallucination ์ œ๊ฑฐ), 1376๊ฐœ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ๊ณจ๋“œ๋ผ๋ฒจ ์ถ”์ถœ, VLM ํ‰๊ฐ€ metric ์„ค๊ณ„ | +| ์ •๋ฏผ์ง€ | ์ƒํ’ˆ ์„ค๋ช… ์š”์•ฝ, ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ์ถ”์ถœ - ์ƒํ’ˆ ์„ค๋ช… ์š”์•ฝ HCX Fine-Tuning, ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ํ‰๊ฐ€ metric ์„ค๊ณ„ ๋ฐ golden label ์ƒ์„ฑ, OCR๊ณผ LLM์„ ํ™œ์šฉํ•œ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ์ถ”์ถœ ๋กœ์ง ์„ค๊ณ„ ๋ฐ ์‹คํ—˜ | + +
+ +## ๐Ÿ“… ํ”„๋กœ์ ํŠธ ํƒ€์ž„๋ผ์ธ + +- ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„์€ 2025-01-10 ~ 2025-02-10์ž…๋‹ˆ๋‹ค. + +![Foodly ํƒ€์ž„๋ผ์ธ](doc/image/foodly_timeline.png) + +
+ +### ๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ + +ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. + +``` +. +|-- README.md +|-- back +| |-- build.gradle # ๋ฐฑ์—”๋“œ ๋นŒ๋“œ ์„ค์ • +| |-- docker-compose.yml # Docker ์„ค์ • ํŒŒ์ผ +| |-- gradle # Gradle ์„ค์ • ๋ฐ wrapper ํŒŒ์ผ +| |-- gradlew # Gradle ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ (Linux/Mac) +| |-- gradlew.bat # Gradle ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ (Windows) +| |-- settings.gradle # ๋ชจ๋“ˆ ์„ค์ • ํŒŒ์ผ +| `-- src # ๋ฐฑ์—”๋“œ ์†Œ์Šค ์ฝ”๋“œ +|-- doc +| |-- image # ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ์ด๋ฏธ์ง€ ์ž๋ฃŒ (๋‹ค์ด์–ด๊ทธ๋žจ, ์Šคํฌ๋ฆฐ์ƒท ๋“ฑ) +| `-- ...pdf # ํ”„๋กœ์ ํŠธ ๋ฐœํ‘œ ์ž๋ฃŒ, ๋ณด๊ณ ์„œ ๋ฌธ์„œ +|-- eda +| |-- README.md # EDA ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ +| |-- eda1_visualize.ipynb # ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” Notebook (EDA ๋‹จ๊ณ„1) +| |-- eda2_visualize.ipynb # ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” Notebook (EDA ๋‹จ๊ณ„2) +| `-- product_crawling.py # ์ œํ’ˆ ๋ฐ์ดํ„ฐ ํฌ๋กค๋ง ์Šคํฌ๋ฆฝํŠธ +|-- front +| |-- chrome_extension # ํฌ๋กฌ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ ๊ด€๋ จ ํ”„๋ก ํŠธ์—”๋“œ ์ฝ”๋“œ +| `-- foodly_application # Foodly ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (๋ชจ๋ฐ”์ผ/์›น) ๊ด€๋ จ ์ฝ”๋“œ, Node.js ๊ธฐ๋ฐ˜ +`-- models + |-- final_outputs # ๋ชจ๋ธ ์‹คํ–‰ ํ›„ ์ƒ์„ฑ๋œ ์ตœ์ข… ๋ฐ์ดํ„ฐ + |-- nutrition_ingredients_information # ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด + | |-- README.md # ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ + | `-- main.py, prompt, src ๋“ฑ + |-- product_summarization # ์ƒํ’ˆ ์ƒ์„ธ์ •๋ณด ์š”์•ฝ + | |-- README.md # ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ + | |-- main.py, prompt, src ๋“ฑ + |-- review # ๋ฆฌ๋ทฐ ์š”์•ฝ ๋ฐ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋ณ„ ์ƒํ’ˆ ์žฌ์ •๋ ฌ + | |-- README.md # ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ + | |-- prompt, src, utils ๋“ฑ + |-- size_description # ์ƒํ’ˆ ํฌ๊ธฐ ์ •๋ณด ์ถ”์ถœ + | |-- README.md # ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ + | |-- src, data, size_info.yaml ๋“ฑ + `-- thumbnail_description # ์ธ๋„ค์ผ ์ด๋ฏธ์ง€ ์„ค๋ช… + |-- README.md # ๋ชจ๋“ˆ ๊ฐœ์š” ๋ฐ ์‹คํ–‰ ๊ฐ€์ด๋“œ + `-- main.py, prompt, src, utils ๋“ฑ + +``` + +
+ +## ๐Ÿ’พ ํ”„๋กœ์ ํŠธ ์„ค์น˜ ๋ฐ ์‹คํ–‰ +๋ณธ ํ”„๋กœ์ ํŠธ๋Š” AI๋ฅผ ํฌํ•จํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ, ๋ฐฑ์—”๋“œ ์‹คํ–‰ ๋ฐฉ๋ฒ•์ด ๊ฐ๊ฐ ๋ณ„๋„๋กœ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ธ ์‹คํ–‰ ๋ฐฉ๋ฒ•์€ ํ•ด๋‹น ํด๋” ๋‚ด์˜ `README.md`์—์„œ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๊ฐ ํŒŒํŠธ์˜ ์ฃผ์š” ์‹คํ–‰ ๋ฐฉ๋ฒ• ์•ˆ๋‚ด์ž…๋‹ˆ๋‹ค. + +### models (๋ชจ๋ธ ๊ด€๋ จ ๋ชจ๋“ˆ) + +๋ชจ๋ธ ๊ด€๋ จ ๋ชจ๋“ˆ์€ ์ด 5๊ฐœ๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ฐ ๋ชจ๋ธ ๋ชจ๋“ˆ์€ ๋…๋ฆฝ์ ์ธ Python ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. + +- `nutrition_ingredients_information/` (์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด) +- `product_summarization/` (์ƒํ’ˆ ์ƒ์„ธ์ •๋ณด ์š”์•ฝ) +- `review/` (๋ฆฌ๋ทฐ ์š”์•ฝ ๋ฐ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋ณ„ ์ƒํ’ˆ ์žฌ์ •๋ ฌ) +- `size_description/` (์ƒํ’ˆ ํฌ๊ธฐ ์ •๋ณด) +- `thumbnail_description/` (์ธ๋„ค์ผ ์ด๋ฏธ์ง€) + +**์‹คํ–‰:** +- `environment.yml` ํŒŒ์ผ์„ ํ™œ์šฉํ•ด Conda ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. +- `python main.py` ๋ช…๋ น์–ด๋กœ ๊ด€๋ จ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +> **์ฃผ์˜:** ๊ฐ ๋ชจ๋“ˆ์˜ ๊ตฌ์ฒด์ ์ธ ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ•์€ ํ•ด๋‹น ๋ชจ๋“ˆ ๋‚ด README๋‚˜ ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. + +### eda (๋ฐ์ดํ„ฐ ํƒ์ƒ‰/๋ถ„์„) + +**์„ค์น˜:** +- Python ๊ฐ€์ƒํ™˜๊ฒฝ(์˜ˆ: Conda)์„ ๊ตฌ์„ฑํ•˜๊ณ , ํ•„์š” ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. (`eda/environment.yml` ํŒŒ์ผ ์ฐธ๊ณ ) + +**์‹คํ–‰:** +- Jupyter Notebook์„ ์‹คํ–‰ํ•˜์—ฌ `eda1_visualize.ipynb`์™€ `eda2_visualize.ipynb` ํŒŒ์ผ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. +- `python product_crawling.py` ๋ช…๋ น์–ด๋กœ ํฌ๋กค๋ง ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +**์ฐธ๊ณ :** ์ƒ์„ธ ๊ฐ€์ด๋“œ๋Š” `eda/README.md`๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. + +### frontend (ํฌ๋กฌ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ/์• ํ”Œ๋ฆฌ์ผ€์ด์…˜) + +#### chrome_extension + +**์„ค์น˜:** +- `npm install`๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. + +**์‹คํ–‰:** +- `npm build`๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ buildํ•ฉ๋‹ˆ๋‹ค. +- ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €์—์„œ '์••์ถ• ํ•ด์ œ๋œ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ'์œผ๋กœ `front/chrome_extension/dist`๋ฅผ ๋กœ๋“œํ•˜๋ฉด ์„ค์น˜ ๋ฐ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. + +#### foodly_application + +**์„ค์น˜:** +- Node.js ๊ธฐ๋ฐ˜์œผ๋กœ, `npm install`๋กœ ์˜์กด์„ฑ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. +- React Native (iOS, Android Application)๋ฅผ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์ด ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ํ™˜๊ฒฝ์„ค์ •์€ [์—ฌ๊ธฐ](https://reactnative.dev/docs/set-up-your-environment)๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”. +- (iOS) `cd front/chrome_extension/ios && pod install`์„ ์ด์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. + +**์‹คํ–‰:** +- (iOS) `npm run ios`๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. +- (Android) `npm run android`๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + + +### backend (์„œ๋ฒ„) + +**์„ค์น˜:** +- `docker-compose.yml`์„ ์ฐธ๊ณ ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ €์žฅํ•˜๋Š” mySQL์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +**์‹คํ–‰:** +- `./gradlew bootRun` ๋ช…๋ น์–ด๋กœ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +**์ฐธ๊ณ :** ์ž์„ธํ•œ ๋‚ด์šฉ์€ `back/README.md`๋ฅผ ํ™•์ธํ•˜์„ธ์š”. diff --git a/back/.gitattributes b/back/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/back/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/back/.gitignore b/back/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/back/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/back/build.gradle b/back/build.gradle new file mode 100644 index 0000000..0929b4a --- /dev/null +++ b/back/build.gradle @@ -0,0 +1,39 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.1' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'com.itsmenlp' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-configuration-processor' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + implementation 'org.mapstruct:mapstruct:1.6.3' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + developmentOnly 'org.springframework.boot:spring-boot-devtools' + runtimeOnly 'com.mysql:mysql-connector-j' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/back/docker-compose.yml b/back/docker-compose.yml new file mode 100644 index 0000000..baf0fd6 --- /dev/null +++ b/back/docker-compose.yml @@ -0,0 +1,14 @@ +services: + mysql: + image: mysql:8-oracle + container_name: foodly_db + ports: + - "3308:3306" + environment: + MYSQL_ROOT_PASSWORD: "nlp_ai_shopper_T734" + MYSQL_DATABASE: foodly + volumes: + - db_data:/var/lib/mysql + +volumes: + db_data: \ No newline at end of file diff --git a/back/gradle/wrapper/gradle-wrapper.jar b/back/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/back/gradle/wrapper/gradle-wrapper.jar differ diff --git a/back/gradle/wrapper/gradle-wrapper.properties b/back/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e2847c8 --- /dev/null +++ b/back/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/back/gradlew b/back/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/back/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/back/gradlew.bat b/back/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/back/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/back/settings.gradle b/back/settings.gradle new file mode 100644 index 0000000..a0223a4 --- /dev/null +++ b/back/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'foodly' diff --git a/back/src/main/java/com/itsmenlp/foodly/FoodlyApplication.java b/back/src/main/java/com/itsmenlp/foodly/FoodlyApplication.java new file mode 100644 index 0000000..0de19e5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/FoodlyApplication.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FoodlyApplication { + + public static void main(String[] args) { + SpringApplication.run(FoodlyApplication.class, args); + } + +} diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/AddressController.java b/back/src/main/java/com/itsmenlp/foodly/controller/AddressController.java new file mode 100644 index 0000000..d0c8dcc --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/AddressController.java @@ -0,0 +1,124 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.AddressRequestDTO; +import com.itsmenlp.foodly.controller.dto.AddressResponseDTO; +import com.itsmenlp.foodly.service.AddressService; +import com.itsmenlp.foodly.service.dto.AddressServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.AddressServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/user/{userId}/address") +@RequiredArgsConstructor +public class AddressController { + + private final AddressService addressService; + + /** + * ์ฃผ์†Œ ์ƒ์„ฑ + * POST /api/user/{userId}/address + */ + @PostMapping + public ResponseEntity createAddress( + @PathVariable Long userId, + @Valid @RequestBody AddressRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + AddressServiceRequestDTO serviceRequestDTO = AddressServiceRequestDTO.builder() + .address(requestDTO.getAddress()) + .build(); + + AddressServiceResponseDTO serviceResponseDTO = addressService.createAddress(userId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + AddressResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ๋ชจ๋“  ์ฃผ์†Œ ์กฐํšŒ + * GET /api/user/{userId}/address + */ + @GetMapping + public ResponseEntity> getAllAddresses(@PathVariable Long userId) { + List serviceResponseDTOs = addressService.getAllAddresses(userId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponseDTOs.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + /** + * ํŠน์ • ์ฃผ์†Œ ์กฐํšŒ + * GET /api/user/{userId}/address/{addressId} + */ + @GetMapping("/{addressId}") + public ResponseEntity getAddressById( + @PathVariable Long userId, + @PathVariable Long addressId) { + + AddressServiceResponseDTO serviceResponseDTO = addressService.getAddressById(userId, addressId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + AddressResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์ฃผ์†Œ ์—…๋ฐ์ดํŠธ + * PUT /api/user/{userId}/address/{addressId} + */ + @PutMapping("/{addressId}") + public ResponseEntity updateAddress( + @PathVariable Long userId, + @PathVariable Long addressId, + @Valid @RequestBody AddressRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + AddressServiceRequestDTO serviceRequestDTO = AddressServiceRequestDTO.builder() + .address(requestDTO.getAddress()) + .build(); + + AddressServiceResponseDTO serviceResponseDTO = addressService.updateAddress(userId, addressId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + AddressResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์ฃผ์†Œ ์‚ญ์ œ + * DELETE /api/user/{userId}/address/{addressId} + */ + @DeleteMapping("/{addressId}") + public ResponseEntity deleteAddress( + @PathVariable Long userId, + @PathVariable Long addressId) { + + addressService.deleteAddress(userId, addressId); + return ResponseEntity.noContent().build(); + } + + private AddressResponseDTO mapToResponseDTO(AddressServiceResponseDTO serviceResponseDTO) { + return AddressResponseDTO.builder() + .addressId(serviceResponseDTO.getAddressId()) + .userId(serviceResponseDTO.getUserId()) + .address(serviceResponseDTO.getAddress()) + .createdAt(serviceResponseDTO.getCreatedAt()) + .updatedAt(serviceResponseDTO.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/CartController.java b/back/src/main/java/com/itsmenlp/foodly/controller/CartController.java new file mode 100644 index 0000000..e03b5d6 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/CartController.java @@ -0,0 +1,127 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.CartRequestDTO; +import com.itsmenlp.foodly.controller.dto.CartResponseDTO; +import com.itsmenlp.foodly.service.CartService; +import com.itsmenlp.foodly.service.dto.CartServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.CartServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/user/{userId}/cart") +@RequiredArgsConstructor +public class CartController { + + private final CartService cartService; + + /** + * ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ ์ถ”๊ฐ€ + * POST /api/user/{userId}/cart + */ + @PostMapping + public ResponseEntity addProductToCart( + @PathVariable Long userId, + @Valid @RequestBody CartRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + CartServiceRequestDTO serviceRequestDTO = CartServiceRequestDTO.builder() + .productId(requestDTO.getProductId()) + .quantity(requestDTO.getQuantity()) + .build(); + + CartServiceResponseDTO serviceResponseDTO = cartService.addProductToCart(userId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + CartResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ๋ชจ๋“  ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ ์กฐํšŒ + * GET /api/user/{userId}/cart + */ + @GetMapping + public ResponseEntity> getAllCartItems(@PathVariable Long userId) { + List serviceResponseDTOs = cartService.getAllCartItems(userId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponseDTOs.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + /** + * ํŠน์ • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ ์กฐํšŒ + * GET /api/user/{userId}/cart/{cartId} + */ + @GetMapping("/{cartId}") + public ResponseEntity getCartItemById( + @PathVariable Long userId, + @PathVariable Long cartId) { + + CartServiceResponseDTO serviceResponseDTO = cartService.getCartItemById(userId, cartId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + CartResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ ์—…๋ฐ์ดํŠธ + * PUT /api/user/{userId}/cart/{cartId} + */ + @PutMapping("/{cartId}") + public ResponseEntity updateCartItem( + @PathVariable Long userId, + @PathVariable Long cartId, + @Valid @RequestBody CartRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + CartServiceRequestDTO serviceRequestDTO = CartServiceRequestDTO.builder() + .productId(requestDTO.getProductId()) + .quantity(requestDTO.getQuantity()) + .build(); + + CartServiceResponseDTO serviceResponseDTO = cartService.updateCartItem(userId, cartId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + CartResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ ์‚ญ์ œ + * DELETE /api/user/{userId}/cart/{cartId} + */ + @DeleteMapping("/{cartId}") + public ResponseEntity deleteCartItem( + @PathVariable Long userId, + @PathVariable Long cartId) { + + cartService.removeCartItem(userId, cartId); + return ResponseEntity.noContent().build(); + } + + private CartResponseDTO mapToResponseDTO(CartServiceResponseDTO serviceResponseDTO) { + return CartResponseDTO.builder() + .cartId(serviceResponseDTO.getCartId()) + .userId(serviceResponseDTO.getUserId()) + .productId(serviceResponseDTO.getProductId()) + .productName(serviceResponseDTO.getProductName()) + .quantity(serviceResponseDTO.getQuantity()) + .addedAt(serviceResponseDTO.getAddedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/CategoryController.java b/back/src/main/java/com/itsmenlp/foodly/controller/CategoryController.java new file mode 100644 index 0000000..25818b5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/CategoryController.java @@ -0,0 +1,159 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.CategoryRequestDTO; +import com.itsmenlp.foodly.controller.dto.CategoryResponseDTO; +import com.itsmenlp.foodly.controller.dto.CategoryAspectRequestDTO; +import com.itsmenlp.foodly.controller.dto.CategoryAspectResponseDTO; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.service.CategoryService; +import com.itsmenlp.foodly.service.CategoryAspectService; +import com.itsmenlp.foodly.service.dto.CategoryCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryUpdateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectUpdateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectServiceResponseDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/category") +public class CategoryController { + + private final CategoryService categoryService; + private final CategoryAspectService categoryAspectService; + + @Autowired + public CategoryController(CategoryService categoryService, CategoryAspectService categoryAspectService) { + this.categoryService = categoryService; + this.categoryAspectService = categoryAspectService; + } + + // ์นดํ…Œ๊ณ ๋ฆฌ CRUD + + @PostMapping + public ResponseEntity createCategory(@Validated @RequestBody CategoryRequestDTO categoryRequestDTO) { + CategoryCreateRequestDTO createDTO = CategoryCreateRequestDTO.builder() + .name(categoryRequestDTO.getName()) + .build(); + CategoryServiceResponseDTO serviceResponse = categoryService.createCategory(createDTO); + CategoryResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + @GetMapping("/{id}") + public ResponseEntity getCategoryById(@PathVariable("id") Long categoryId) { + CategoryServiceResponseDTO serviceResponse = categoryService.getCategoryById(categoryId); + CategoryResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @GetMapping + public ResponseEntity> getAllCategories() { + List serviceResponses = categoryService.getAllCategories(); + List responseDTOs = serviceResponses.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseDTOs); + } + + @PutMapping("/{id}") + public ResponseEntity updateCategory( + @PathVariable("id") Long categoryId, + @Validated @RequestBody CategoryRequestDTO categoryRequestDTO) { + CategoryUpdateRequestDTO updateDTO = CategoryUpdateRequestDTO.builder() + .name(categoryRequestDTO.getName()) + .build(); + CategoryServiceResponseDTO serviceResponse = categoryService.updateCategory(categoryId, updateDTO); + CategoryResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteCategory(@PathVariable("id") Long categoryId) { + categoryService.deleteCategory(categoryId); + return ResponseEntity.noContent().build(); + } + + // ์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด Aspect CRUD + @PostMapping("/{categoryId}/aspects") + public ResponseEntity createAspect( + @PathVariable("categoryId") Long categoryId, + @Validated @RequestBody CategoryAspectRequestDTO aspectRequestDTO) { + CategoryAspectCreateRequestDTO createDTO = CategoryAspectCreateRequestDTO.builder() + .aspect(aspectRequestDTO.getAspect()) + .build(); + CategoryAspectServiceResponseDTO serviceResponse = categoryAspectService.createAspect(categoryId, createDTO); + CategoryAspectResponseDTO responseDTO = mapToAspectResponseDTO(serviceResponse); + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + @GetMapping("/{categoryId}/aspects") + public ResponseEntity> getAllAspectsByCategory(@PathVariable("categoryId") Long categoryId) { + List serviceResponses = categoryAspectService.getAllAspectsByCategory(categoryId); + List responseDTOs = serviceResponses.stream() + .map(this::mapToAspectResponseDTO) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseDTOs); + } + + @GetMapping("/aspects/{id}") + public ResponseEntity getAspectById(@PathVariable("id") Long aspectId) { + CategoryAspectServiceResponseDTO serviceResponse = categoryAspectService.getAspectById(aspectId); + CategoryAspectResponseDTO responseDTO = mapToAspectResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @PutMapping("/aspects/{id}") + public ResponseEntity updateAspect( + @PathVariable("id") Long aspectId, + @Validated @RequestBody CategoryAspectRequestDTO aspectRequestDTO) { + CategoryAspectUpdateRequestDTO updateDTO = CategoryAspectUpdateRequestDTO.builder() + .aspect(aspectRequestDTO.getAspect()) + .build(); + CategoryAspectServiceResponseDTO serviceResponse = categoryAspectService.updateAspect(aspectId, updateDTO); + CategoryAspectResponseDTO responseDTO = mapToAspectResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @DeleteMapping("/aspects/{id}") + public ResponseEntity deleteAspect(@PathVariable("id") Long aspectId) { + categoryAspectService.deleteAspect(aspectId); + return ResponseEntity.noContent().build(); + } + + // DTO ๋งคํ•‘ ๋ฉ”์„œ๋“œ + + private CategoryResponseDTO mapToResponseDTO(CategoryServiceResponseDTO serviceResponse) { + return CategoryResponseDTO.builder() + .categoryId(serviceResponse.getCategoryId()) + .name(serviceResponse.getName()) + .createdAt(serviceResponse.getCreatedAt()) + .updatedAt(serviceResponse.getUpdatedAt()) + .aspects( + serviceResponse.getAspects().stream() + .map(this::mapToAspectResponseDTO) + .collect(Collectors.toList()) + ) + .build(); + } + + private CategoryAspectResponseDTO mapToAspectResponseDTO(CategoryAspectServiceResponseDTO serviceResponse) { + return CategoryAspectResponseDTO.builder() + .id(serviceResponse.getId()) + .aspect(serviceResponse.getAspect()) + .build(); + } + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex){ + return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); + } + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/DescriptionController.java b/back/src/main/java/com/itsmenlp/foodly/controller/DescriptionController.java new file mode 100644 index 0000000..3708460 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/DescriptionController.java @@ -0,0 +1,167 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.DescriptionRequestDTO; +import com.itsmenlp.foodly.controller.dto.DescriptionResponseDTO; +import com.itsmenlp.foodly.service.DescriptionService; +import com.itsmenlp.foodly.service.dto.DescriptionServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.DescriptionServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/descriptions") +@RequiredArgsConstructor +public class DescriptionController { + + private final DescriptionService descriptionService; + + /** + * ์ƒํ’ˆ ์„ค๋ช… ์ƒ์„ฑ + * POST /api/descriptions/{productId} + */ + @PostMapping("/{productId}") + public ResponseEntity createDescription( + @PathVariable Long productId, + @RequestBody DescriptionRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + DescriptionServiceRequestDTO serviceRequestDTO = DescriptionServiceRequestDTO.builder() + .summaryExp(requestDTO.getSummaryExp()) + .summaryCook(requestDTO.getSummaryCook()) + .summaryStore(requestDTO.getSummaryStore()) + .cautionAllergy1(requestDTO.getCautionAllergy1()) + .cautionAllergy2(requestDTO.getCautionAllergy2()) + .cautionStore(requestDTO.getCautionStore()) + .sizeDescription(requestDTO.getSizeDescription()) + .sizeImageUrl(requestDTO.getSizeImageUrl()) + .nutrition(requestDTO.getNutrition()) + .ingredient(requestDTO.getIngredient()) + .reviewGoodTaste(requestDTO.getReviewGoodTaste()) + .reviewGoodTasteNum(requestDTO.getReviewGoodTasteNum()) + .reviewGoodDelivery(requestDTO.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(requestDTO.getReviewGoodDeliveryNum()) + .reviewBadTaste(requestDTO.getReviewBadTaste()) + .reviewBadTasteNum(requestDTO.getReviewBadTasteNum()) + .reviewBadDelivery(requestDTO.getReviewBadDelivery()) + .reviewBadDeliveryNum(requestDTO.getReviewBadDeliveryNum()) + .build(); + + DescriptionServiceResponseDTO serviceResponseDTO = descriptionService.createDescription(productId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + DescriptionResponseDTO responseDTO = DescriptionResponseDTO.builder() + .productId(serviceResponseDTO.getProductId()) + .summaryExp(serviceResponseDTO.getSummaryExp()) + .summaryCook(serviceResponseDTO.getSummaryCook()) + .summaryStore(serviceResponseDTO.getSummaryStore()) + .cautionAllergy1(serviceResponseDTO.getCautionAllergy1()) + .cautionAllergy2(serviceResponseDTO.getCautionAllergy2()) + .cautionStore(serviceResponseDTO.getCautionStore()) + .sizeDescription(serviceResponseDTO.getSizeDescription()) + .sizeImageUrl(serviceResponseDTO.getSizeImageUrl()) + .nutrition(serviceResponseDTO.getNutrition()) + .ingredient(serviceResponseDTO.getIngredient()) + .reviewGoodTaste(serviceResponseDTO.getReviewGoodTaste()) + .reviewGoodTasteNum(serviceResponseDTO.getReviewGoodTasteNum()) + .reviewGoodDelivery(serviceResponseDTO.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(serviceResponseDTO.getReviewGoodDeliveryNum()) + .reviewBadTaste(serviceResponseDTO.getReviewBadTaste()) + .reviewBadTasteNum(serviceResponseDTO.getReviewBadTasteNum()) + .reviewBadDelivery(serviceResponseDTO.getReviewBadDelivery()) + .reviewBadDeliveryNum(serviceResponseDTO.getReviewBadDeliveryNum()) + .createdAt(serviceResponseDTO.getCreatedAt()) + .updatedAt(serviceResponseDTO.getUpdatedAt()) + .build(); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ์ƒํ’ˆ ์„ค๋ช… ์กฐํšŒ + * GET /api/descriptions/{productId} + */ + @GetMapping("/{productId}") + public ResponseEntity getDescription(@PathVariable Long productId) { + DescriptionServiceResponseDTO serviceResponseDTO = descriptionService.getDescription(productId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + return getDescriptionResponseDTOResponseEntity(serviceResponseDTO); + } + + /** + * ์ƒํ’ˆ ์„ค๋ช… ์—…๋ฐ์ดํŠธ + * PUT /api/descriptions/{productId} + */ + @PutMapping("/{productId}") + public ResponseEntity updateDescription( + @PathVariable Long productId, + @RequestBody DescriptionRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + DescriptionServiceRequestDTO serviceRequestDTO = DescriptionServiceRequestDTO.builder() + .summaryExp(requestDTO.getSummaryExp()) + .summaryCook(requestDTO.getSummaryCook()) + .summaryStore(requestDTO.getSummaryStore()) + .cautionAllergy1(requestDTO.getCautionAllergy1()) + .cautionAllergy2(requestDTO.getCautionAllergy2()) + .cautionStore(requestDTO.getCautionStore()) + .sizeDescription(requestDTO.getSizeDescription()) + .sizeImageUrl(requestDTO.getSizeImageUrl()) + .nutrition(requestDTO.getNutrition()) + .ingredient(requestDTO.getIngredient()) + .reviewGoodTaste(requestDTO.getReviewGoodTaste()) + .reviewGoodTasteNum(requestDTO.getReviewGoodTasteNum()) + .reviewGoodDelivery(requestDTO.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(requestDTO.getReviewGoodDeliveryNum()) + .reviewBadTaste(requestDTO.getReviewBadTaste()) + .reviewBadTasteNum(requestDTO.getReviewBadTasteNum()) + .reviewBadDelivery(requestDTO.getReviewBadDelivery()) + .reviewBadDeliveryNum(requestDTO.getReviewBadDeliveryNum()) + .build(); + + DescriptionServiceResponseDTO serviceResponseDTO = descriptionService.updateDescription(productId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + return getDescriptionResponseDTOResponseEntity(serviceResponseDTO); + } + + /** + * ์ƒํ’ˆ ์„ค๋ช… ์‚ญ์ œ + * DELETE /api/descriptions/{productId} + */ + @DeleteMapping("/{productId}") + public ResponseEntity deleteDescription(@PathVariable Long productId) { + descriptionService.deleteDescription(productId); + return ResponseEntity.noContent().build(); + } + + private ResponseEntity getDescriptionResponseDTOResponseEntity(DescriptionServiceResponseDTO serviceResponseDTO) { + DescriptionResponseDTO responseDTO = DescriptionResponseDTO.builder() + .productId(serviceResponseDTO.getProductId()) + .summaryExp(serviceResponseDTO.getSummaryExp()) + .summaryCook(serviceResponseDTO.getSummaryCook()) + .summaryStore(serviceResponseDTO.getSummaryStore()) + .cautionAllergy1(serviceResponseDTO.getCautionAllergy1()) + .cautionAllergy2(serviceResponseDTO.getCautionAllergy2()) + .cautionStore(serviceResponseDTO.getCautionStore()) + .sizeDescription(serviceResponseDTO.getSizeDescription()) + .sizeImageUrl(serviceResponseDTO.getSizeImageUrl()) + .nutrition(serviceResponseDTO.getNutrition()) + .ingredient(serviceResponseDTO.getIngredient()) + .reviewGoodTaste(serviceResponseDTO.getReviewGoodTaste()) + .reviewGoodTasteNum(serviceResponseDTO.getReviewGoodTasteNum()) + .reviewGoodDelivery(serviceResponseDTO.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(serviceResponseDTO.getReviewGoodDeliveryNum()) + .reviewBadTaste(serviceResponseDTO.getReviewBadTaste()) + .reviewBadTasteNum(serviceResponseDTO.getReviewBadTasteNum()) + .reviewBadDelivery(serviceResponseDTO.getReviewBadDelivery()) + .reviewBadDeliveryNum(serviceResponseDTO.getReviewBadDeliveryNum()) + .createdAt(serviceResponseDTO.getCreatedAt()) + .updatedAt(serviceResponseDTO.getUpdatedAt()) + .build(); + + return ResponseEntity.ok(responseDTO); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/ImageToTextController.java b/back/src/main/java/com/itsmenlp/foodly/controller/ImageToTextController.java new file mode 100644 index 0000000..a355879 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/ImageToTextController.java @@ -0,0 +1,39 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.ImageToTextRequestDTO; +import com.itsmenlp.foodly.controller.dto.ImageToTextResponseDTO; +import com.itsmenlp.foodly.service.ImageToTextService; +import com.itsmenlp.foodly.service.dto.ImageToTextServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ImageToTextServiceResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/image-to-text") +public class ImageToTextController { + + private final ImageToTextService imageToTextService; + + public ImageToTextController(ImageToTextService imageToTextService) { + this.imageToTextService = imageToTextService; + } + + @PostMapping("/process") + public ResponseEntity process(@RequestBody ImageToTextRequestDTO request) { + // Controller DTO -> Service DTO ๋งคํ•‘ + ImageToTextServiceRequestDTO serviceRequest = new ImageToTextServiceRequestDTO(); + serviceRequest.setLink(request.getLink()); + serviceRequest.setImages(request.getImages()); + + ImageToTextServiceResponseDTO serviceResponse = imageToTextService.processInput(serviceRequest); + + // Service DTO -> Controller DTO ๋งคํ•‘ + ImageToTextResponseDTO response = new ImageToTextResponseDTO(); + response.setId(serviceResponse.getId()); + response.setLink(serviceResponse.getLink()); + response.setImages(serviceResponse.getInputImages()); + response.setTexts(serviceResponse.getOutputTexts()); + + return ResponseEntity.ok(response); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/OrderController.java b/back/src/main/java/com/itsmenlp/foodly/controller/OrderController.java new file mode 100644 index 0000000..e613c1e --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/OrderController.java @@ -0,0 +1,162 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.OrderRequestDTO; +import com.itsmenlp.foodly.controller.dto.OrderResponseDTO; +import com.itsmenlp.foodly.service.OrderService; +import com.itsmenlp.foodly.service.dto.OrderServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.OrderServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/user/{userId}/order") +@RequiredArgsConstructor +public class OrderController { + + private final OrderService orderService; + + /** + * ์ฃผ๋ฌธ ์ƒ์„ฑ + * POST /api/user/{userId}/order + */ + @PostMapping + public ResponseEntity createOrder( + @PathVariable Long userId, + @Valid @RequestBody OrderRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + OrderServiceRequestDTO serviceRequestDTO = OrderServiceRequestDTO.builder() + .paymentId(requestDTO.getPaymentId()) + .addressId(requestDTO.getAddressId()) + .orderStatus(requestDTO.getOrderStatus()) + .totalAmount(requestDTO.getTotalAmount()) + .orderItems( + requestDTO.getOrderItems().stream() + .map(itemDTO -> com.itsmenlp.foodly.service.dto.OrderItemServiceRequestDTO.builder() + .productId(itemDTO.getProductId()) + .quantity(itemDTO.getQuantity()) + .unitPrice(itemDTO.getUnitPrice()) + .build()) + .collect(Collectors.toList()) + ) + .build(); + + OrderServiceResponseDTO serviceResponseDTO = orderService.createOrder(userId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + OrderResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ + * GET /api/user/{userId}/order + */ + @GetMapping + public ResponseEntity> getAllOrders(@PathVariable Long userId) { + List serviceResponseDTOs = orderService.getAllOrders(userId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponseDTOs.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + /** + * ํŠน์ • ์ฃผ๋ฌธ ์กฐํšŒ + * GET /api/user/{userId}/order/{orderId} + */ + @GetMapping("/{orderId}") + public ResponseEntity getOrderById( + @PathVariable Long userId, + @PathVariable Long orderId) { + + OrderServiceResponseDTO serviceResponseDTO = orderService.getOrderById(userId, orderId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + OrderResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์ฃผ๋ฌธ ์—…๋ฐ์ดํŠธ + * PUT /api/user/{userId}/order/{orderId} + */ + @PutMapping("/{orderId}") + public ResponseEntity updateOrder( + @PathVariable Long userId, + @PathVariable Long orderId, + @Valid @RequestBody OrderRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + OrderServiceRequestDTO serviceRequestDTO = OrderServiceRequestDTO.builder() + .paymentId(requestDTO.getPaymentId()) + .addressId(requestDTO.getAddressId()) + .orderStatus(requestDTO.getOrderStatus()) + .totalAmount(requestDTO.getTotalAmount()) + .orderItems( + requestDTO.getOrderItems().stream() + .map(itemDTO -> com.itsmenlp.foodly.service.dto.OrderItemServiceRequestDTO.builder() + .productId(itemDTO.getProductId()) + .quantity(itemDTO.getQuantity()) + .unitPrice(itemDTO.getUnitPrice()) + .build()) + .collect(Collectors.toList()) + ) + .build(); + + OrderServiceResponseDTO serviceResponseDTO = orderService.updateOrder(userId, orderId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + OrderResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ์ฃผ๋ฌธ ์‚ญ์ œ + * DELETE /api/user/{userId}/order/{orderId} + */ + @DeleteMapping("/{orderId}") + public ResponseEntity deleteOrder( + @PathVariable Long userId, + @PathVariable Long orderId) { + + orderService.deleteOrder(userId, orderId); + return ResponseEntity.noContent().build(); + } + + private OrderResponseDTO mapToResponseDTO(OrderServiceResponseDTO serviceResponseDTO) { + List orderItemsDTO = serviceResponseDTO.getOrderItems().stream() + .map(item -> com.itsmenlp.foodly.controller.dto.OrderItemResponseDTO.builder() + .orderItemId(item.getOrderItemId()) + .productId(item.getProductId()) + .productName(item.getProductName()) + .quantity(item.getQuantity()) + .unitPrice(item.getUnitPrice()) + .build()) + .collect(Collectors.toList()); + + return OrderResponseDTO.builder() + .orderId(serviceResponseDTO.getOrderId()) + .userId(serviceResponseDTO.getUserId()) + .paymentId(serviceResponseDTO.getPaymentId()) + .addressId(serviceResponseDTO.getAddressId()) + .orderStatus(serviceResponseDTO.getOrderStatus()) + .totalAmount(serviceResponseDTO.getTotalAmount()) + .createdAt(serviceResponseDTO.getCreatedAt()) + .updatedAt(serviceResponseDTO.getUpdatedAt()) + .orderItems(orderItemsDTO) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/PaymentController.java b/back/src/main/java/com/itsmenlp/foodly/controller/PaymentController.java new file mode 100644 index 0000000..2818fad --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/PaymentController.java @@ -0,0 +1,126 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.PaymentRequestDTO; +import com.itsmenlp.foodly.controller.dto.PaymentResponseDTO; +import com.itsmenlp.foodly.service.PaymentService; +import com.itsmenlp.foodly.service.dto.PaymentServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.PaymentServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/user/{userId}/payment") +@RequiredArgsConstructor +public class PaymentController { + + private final PaymentService paymentService; + + /** + * ๊ฒฐ์ œ ์ •๋ณด ์ƒ์„ฑ + * POST /api/user/{userId}/payment + */ + @PostMapping + public ResponseEntity createPayment( + @PathVariable Long userId, + @Valid @RequestBody PaymentRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + PaymentServiceRequestDTO serviceRequestDTO = PaymentServiceRequestDTO.builder() + .status(requestDTO.getStatus()) + .paymentAmount(requestDTO.getPaymentAmount()) + .build(); + + PaymentServiceResponseDTO serviceResponseDTO = paymentService.createPayment(userId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + PaymentResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ๋ชจ๋“  ๊ฒฐ์ œ ์ •๋ณด ์กฐํšŒ + * GET /api/user/{userId}/payment + */ + @GetMapping + public ResponseEntity> getAllPayments(@PathVariable Long userId) { + List serviceResponseDTOs = paymentService.getAllPayments(userId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponseDTOs.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + /** + * ํŠน์ • ๊ฒฐ์ œ ์ •๋ณด ์กฐํšŒ + * GET /api/user/{userId}/payment/{paymentId} + */ + @GetMapping("/{paymentId}") + public ResponseEntity getPaymentById( + @PathVariable Long userId, + @PathVariable Long paymentId) { + + PaymentServiceResponseDTO serviceResponseDTO = paymentService.getPaymentById(userId, paymentId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + PaymentResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ๊ฒฐ์ œ ์ •๋ณด ์—…๋ฐ์ดํŠธ + * PUT /api/user/{userId}/payment/{paymentId} + */ + @PutMapping("/{paymentId}") + public ResponseEntity updatePayment( + @PathVariable Long userId, + @PathVariable Long paymentId, + @Valid @RequestBody PaymentRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + PaymentServiceRequestDTO serviceRequestDTO = PaymentServiceRequestDTO.builder() + .status(requestDTO.getStatus()) + .paymentAmount(requestDTO.getPaymentAmount()) + .build(); + + PaymentServiceResponseDTO serviceResponseDTO = paymentService.updatePayment(userId, paymentId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + PaymentResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ๊ฒฐ์ œ ์ •๋ณด ์‚ญ์ œ + * DELETE /api/user/{userId}/payment/{paymentId} + */ + @DeleteMapping("/{paymentId}") + public ResponseEntity deletePayment( + @PathVariable Long userId, + @PathVariable Long paymentId) { + + paymentService.deletePayment(userId, paymentId); + return ResponseEntity.noContent().build(); + } + + private PaymentResponseDTO mapToResponseDTO(PaymentServiceResponseDTO serviceResponseDTO) { + return PaymentResponseDTO.builder() + .paymentId(serviceResponseDTO.getPaymentId()) + .userId(serviceResponseDTO.getUserId()) + .status(serviceResponseDTO.getStatus()) + .paymentAmount(serviceResponseDTO.getPaymentAmount()) + .paymentDate(serviceResponseDTO.getPaymentDate()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/ProductController.java b/back/src/main/java/com/itsmenlp/foodly/controller/ProductController.java new file mode 100644 index 0000000..f1ef3e2 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/ProductController.java @@ -0,0 +1,147 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.ProductRequestDTO; +import com.itsmenlp.foodly.controller.dto.ProductResponseDTO; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.service.ProductService; +import com.itsmenlp.foodly.service.dto.ProductCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.ProductServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.ProductUpdateRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/product") +public class ProductController { + + private final ProductService productService; + + @Autowired + public ProductController(ProductService productService) { + this.productService = productService; + } + + // ์ƒํ’ˆ ์ƒ์„ฑ + @PostMapping + public ResponseEntity createProduct(@Validated @RequestBody ProductRequestDTO productRequestDTO) { + ProductCreateRequestDTO createDTO = ProductCreateRequestDTO.builder() + .categoryId(productRequestDTO.getCategoryId()) + .name(productRequestDTO.getName()) + .thumbnailUrl(productRequestDTO.getThumbnailUrl()) + .thumbnailCaption(productRequestDTO.getThumbnailCaption()) + .thumbnailCaptionShort(productRequestDTO.getThumbnailCaptionShort()) + .mall(productRequestDTO.getMall()) + .price(productRequestDTO.getPrice()) + .stock(productRequestDTO.getStock()) + .rating(productRequestDTO.getRating()) + .coupon(productRequestDTO.getCoupon()) + .delivery(productRequestDTO.getDelivery()) + .build(); + ProductServiceResponseDTO serviceResponse = productService.createProduct(createDTO); + ProductResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + // ํŠน์ • ์ƒํ’ˆ ์กฐํšŒ + @GetMapping("/{id:\\d+}") + public ResponseEntity getProductById(@PathVariable("id") Long productId) { + ProductServiceResponseDTO serviceResponse = productService.getProductById(productId); + ProductResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + // ๋ชจ๋“  ์ƒํ’ˆ ์กฐํšŒ + @GetMapping + public ResponseEntity> getAllProducts() { + List serviceResponses = productService.getAllProducts(); + List responseDTOs = serviceResponses.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseDTOs); + } + + // ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ƒํ’ˆ ์กฐํšŒ + @GetMapping("/categories/{categoryId}") + public ResponseEntity> getProductsByCategoryId(@PathVariable("categoryId") Long categoryId) { + List serviceResponses = productService.getProductsByCategoryId(categoryId); + List responseDTOs = serviceResponses.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseDTOs); + } + + // ์ƒํ’ˆ ์—…๋ฐ์ดํŠธ + @PutMapping("/{id}") + public ResponseEntity updateProduct( + @PathVariable("id") Long productId, + @Validated @RequestBody ProductRequestDTO productRequestDTO) { + ProductUpdateRequestDTO updateDTO = ProductUpdateRequestDTO.builder() + .categoryId(productRequestDTO.getCategoryId()) + .name(productRequestDTO.getName()) + .thumbnailUrl(productRequestDTO.getThumbnailUrl()) + .thumbnailCaption(productRequestDTO.getThumbnailCaption()) + .thumbnailCaptionShort(productRequestDTO.getThumbnailCaptionShort()) + .mall(productRequestDTO.getMall()) + .price(productRequestDTO.getPrice()) + .stock(productRequestDTO.getStock()) + .rating(productRequestDTO.getRating()) + .coupon(productRequestDTO.getCoupon()) + .delivery(productRequestDTO.getDelivery()) + .build(); + ProductServiceResponseDTO serviceResponse = productService.updateProduct(productId, updateDTO); + ProductResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + // ์ƒํ’ˆ ์‚ญ์ œ + @DeleteMapping("/{id}") + public ResponseEntity deleteProduct(@PathVariable("id") Long productId) { + productService.deleteProduct(productId); + return ResponseEntity.noContent().build(); + } + + // DTO ๋งคํ•‘ ๋ฉ”์„œ๋“œ + private ProductResponseDTO mapToResponseDTO(ProductServiceResponseDTO serviceResponse) { + return ProductResponseDTO.builder() + .productId(serviceResponse.getProductId()) + .categoryId(serviceResponse.getCategoryId()) + .name(serviceResponse.getName()) + .thumbnailUrl(serviceResponse.getThumbnailUrl()) + .thumbnailCaption(serviceResponse.getThumbnailCaption()) + .thumbnailCaptionShort(serviceResponse.getThumbnailCaptionShort()) + .mall(serviceResponse.getMall()) + .price(serviceResponse.getPrice()) + .stock(serviceResponse.getStock()) + .rating(serviceResponse.getRating()) + .coupon(serviceResponse.getCoupon()) + .delivery(serviceResponse.getDelivery()) + .createdAt(serviceResponse.getCreatedAt()) + .updatedAt(serviceResponse.getUpdatedAt()) + .build(); + } + + // (์˜ˆ์‹œ) ์ด๋ฆ„ ๊ฒ€์ƒ‰ + @GetMapping("/search") + public ResponseEntity> getProductsByName(@RequestParam("name") String name) { + // Service๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ + List serviceResponses = productService.getProductsByName(name); + + // Controller์—์„œ ์“ฐ๋Š” DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponses.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex){ + return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/ProductRankController.java b/back/src/main/java/com/itsmenlp/foodly/controller/ProductRankController.java new file mode 100644 index 0000000..f8201c4 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/ProductRankController.java @@ -0,0 +1,101 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.ProductRankRequestDTO; +import com.itsmenlp.foodly.controller.dto.ProductRankResponseDTO; +import com.itsmenlp.foodly.service.ProductRankService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/rank") +public class ProductRankController { + + @Autowired + private ProductRankService productRankService; + + // Service DTO -> Controller DTO ๋ณ€ํ™˜ + private ProductRankResponseDTO convertToResponse(com.itsmenlp.foodly.service.dto.ProductRankResponseDTO dto) { + return new ProductRankResponseDTO( + dto.getProductRankId(), + dto.getProductId(), + dto.getAspectId(), + dto.getCategoryId(), + dto.getProductRank() + ); + } + + // ๋“ฑ๋ก (Create) + @PostMapping + public ProductRankResponseDTO createProductRank(@RequestBody ProductRankRequestDTO request) { + com.itsmenlp.foodly.service.dto.ProductRankRequestDTO requestDTO = new com.itsmenlp.foodly.service.dto.ProductRankRequestDTO( + request.getProductRankId(), + request.getProductId(), + request.getAspectId(), + request.getCategoryId(), + request.getProductRank() + ); + com.itsmenlp.foodly.service.dto.ProductRankResponseDTO responseDTO = productRankService.createProductRank(requestDTO); + return convertToResponse(responseDTO); + } + + // ์ „์ฒด ๋ชฉ๋ก ์กฐํšŒ (Read All) + @GetMapping + public List getAllProductRanks() { + return productRankService.getAllProductRanks() + .stream() + .map(this::convertToResponse) + .collect(Collectors.toList()); + } + + // ๋‹จ๊ฑด ์กฐํšŒ (Read) + @GetMapping("/{productRankId}/{productId}/{aspectId}/{categoryId}") + public ProductRankResponseDTO getProductRank( + @PathVariable Integer productRankId, + @PathVariable Integer productId, + @PathVariable Integer aspectId, + @PathVariable Integer categoryId) { + com.itsmenlp.foodly.service.dto.ProductRankResponseDTO responseDTO = productRankService.getProductRank(productRankId, productId, aspectId, categoryId); + return convertToResponse(responseDTO); + } + + // ์ˆ˜์ • (Update) + @PutMapping("/{productRankId}/{productId}/{aspectId}/{categoryId}") + public ProductRankResponseDTO updateProductRank( + @PathVariable Integer productRankId, + @PathVariable Integer productId, + @PathVariable Integer aspectId, + @PathVariable Integer categoryId, + @RequestBody ProductRankRequestDTO request) { + com.itsmenlp.foodly.service.dto.ProductRankRequestDTO requestDto = new com.itsmenlp.foodly.service.dto.ProductRankRequestDTO( + request.getProductRankId(), + request.getProductId(), + request.getAspectId(), + request.getCategoryId(), + request.getProductRank() + ); + com.itsmenlp.foodly.service.dto.ProductRankResponseDTO responseDTO = productRankService.updateProductRank(productRankId, productId, aspectId, categoryId, requestDto); + return convertToResponse(responseDTO); + } + + // ์‚ญ์ œ (Delete) + @DeleteMapping("/{productRankId}/{productId}/{aspectId}/{categoryId}") + public void deleteProductRank( + @PathVariable Integer productRankId, + @PathVariable Integer productId, + @PathVariable Integer aspectId, + @PathVariable Integer categoryId) { + productRankService.deleteProductRank(productRankId, productId, aspectId, categoryId); + } + + // ํŠน์ • aspect_id์˜ ๋ฐ์ดํ„ฐ๋ฅผ rank(=COUNT) ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ์กฐํšŒ + @GetMapping("/aspect/{aspectId}") + public List getProductRanksByAspect(@PathVariable Integer aspectId) { + return productRankService.getProductRanksByAspect(aspectId) + .stream() + .map(this::convertToResponse) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/ReviewController.java b/back/src/main/java/com/itsmenlp/foodly/controller/ReviewController.java new file mode 100644 index 0000000..731f365 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/ReviewController.java @@ -0,0 +1,127 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.ReviewRequestDTO; +import com.itsmenlp.foodly.controller.dto.ReviewResponseDTO; +import com.itsmenlp.foodly.service.ReviewService; +import com.itsmenlp.foodly.service.dto.ReviewServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ReviewServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/product/{productId}/review") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + /** + * ๋ฆฌ๋ทฐ ์ƒ์„ฑ + * POST /api/products/{productId}/review + */ + @PostMapping + public ResponseEntity createReview( + @PathVariable Long productId, + @Valid @RequestBody ReviewRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + ReviewServiceRequestDTO serviceRequestDTO = ReviewServiceRequestDTO.builder() + .rate(requestDTO.getRate()) + .comment(requestDTO.getComment()) + .build(); + + ReviewServiceResponseDTO serviceResponseDTO = reviewService.createReview(productId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + ReviewResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + /** + * ๋ชจ๋“  ๋ฆฌ๋ทฐ ์กฐํšŒ + * GET /api/products/{productId}/review + */ + @GetMapping + public ResponseEntity> getAllReviews(@PathVariable Long productId) { + List serviceResponseDTOs = reviewService.getAllReviews(productId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + List responseDTOs = serviceResponseDTOs.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + + return ResponseEntity.ok(responseDTOs); + } + + /** + * ํŠน์ • ๋ฆฌ๋ทฐ ์กฐํšŒ + * GET /api/products/{productId}/reviews/{reviewId} + */ + @GetMapping("/{reviewId}") + public ResponseEntity getReviewById( + @PathVariable Long productId, + @PathVariable Long reviewId) { + + ReviewServiceResponseDTO serviceResponseDTO = reviewService.getReviewById(productId, reviewId); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + ReviewResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ๋ฆฌ๋ทฐ ์—…๋ฐ์ดํŠธ + * PUT /api/products/{productId}/reviews/{reviewId} + */ + @PutMapping("/{reviewId}") + public ResponseEntity updateReview( + @PathVariable Long productId, + @PathVariable Long reviewId, + @Valid @RequestBody ReviewRequestDTO requestDTO) { + + // Controller DTO๋ฅผ Service DTO๋กœ ๋ณ€ํ™˜ + ReviewServiceRequestDTO serviceRequestDTO = ReviewServiceRequestDTO.builder() + .rate(requestDTO.getRate()) + .comment(requestDTO.getComment()) + .build(); + + ReviewServiceResponseDTO serviceResponseDTO = reviewService.updateReview(productId, reviewId, serviceRequestDTO); + + // Service DTO๋ฅผ Controller DTO๋กœ ๋ณ€ํ™˜ + ReviewResponseDTO responseDTO = mapToResponseDTO(serviceResponseDTO); + + return ResponseEntity.ok(responseDTO); + } + + /** + * ๋ฆฌ๋ทฐ ์‚ญ์ œ + * DELETE /api/products/{productId}/reviews/{reviewId} + */ + @DeleteMapping("/{reviewId}") + public ResponseEntity deleteReview( + @PathVariable Long productId, + @PathVariable Long reviewId) { + + reviewService.deleteReview(productId, reviewId); + return ResponseEntity.noContent().build(); + } + + private ReviewResponseDTO mapToResponseDTO(ReviewServiceResponseDTO serviceResponseDTO) { + return ReviewResponseDTO.builder() + .reviewId(serviceResponseDTO.getReviewId()) + .productId(serviceResponseDTO.getProductId()) + .rate(serviceResponseDTO.getRate()) + .comment(serviceResponseDTO.getComment()) + .createdAt(serviceResponseDTO.getCreatedAt()) + .updatedAt(serviceResponseDTO.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/UserController.java b/back/src/main/java/com/itsmenlp/foodly/controller/UserController.java new file mode 100644 index 0000000..5bd6f87 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/UserController.java @@ -0,0 +1,91 @@ +package com.itsmenlp.foodly.controller; + +import com.itsmenlp.foodly.controller.dto.UserRequestDTO; +import com.itsmenlp.foodly.controller.dto.UserResponseDTO; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.service.UserService; +import com.itsmenlp.foodly.service.dto.UserCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.UserServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.UserUpdateRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/user") +public class UserController { + + private final UserService userService; + + @Autowired + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping + public ResponseEntity createUser(@Validated @RequestBody UserRequestDTO userRequestDTO) { + UserCreateRequestDTO createDTO = UserCreateRequestDTO.builder() + .email(userRequestDTO.getEmail()) + .username(userRequestDTO.getUsername()) + .build(); + UserServiceResponseDTO serviceResponse = userService.createUser(createDTO); + UserResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); + } + + @GetMapping("/{id}") + public ResponseEntity getUserById(@PathVariable("id") Long userId) { + UserServiceResponseDTO serviceResponse = userService.getUserById(userId); + UserResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @GetMapping + public ResponseEntity> getAllUsers() { + List serviceResponses = userService.getAllUsers(); + List responseDTOs = serviceResponses.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseDTOs); + } + + @PutMapping("/{id}") + public ResponseEntity updateUser( + @PathVariable("id") Long userId, + @Validated @RequestBody UserRequestDTO userRequestDTO) { + UserUpdateRequestDTO updateDTO = UserUpdateRequestDTO.builder() + .username(userRequestDTO.getUsername()) + .build(); + UserServiceResponseDTO serviceResponse = userService.updateUser(userId, updateDTO); + UserResponseDTO responseDTO = mapToResponseDTO(serviceResponse); + return ResponseEntity.ok(responseDTO); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@PathVariable("id") Long userId) { + userService.deleteUser(userId); + return ResponseEntity.noContent().build(); + } + + private UserResponseDTO mapToResponseDTO(UserServiceResponseDTO serviceResponse) { + return UserResponseDTO.builder() + .userId(serviceResponse.getUserId()) + .email(serviceResponse.getEmail()) + .username(serviceResponse.getUsername()) + .createdAt(serviceResponse.getCreatedAt()) + .updatedAt(serviceResponse.getUpdatedAt()) + .build(); + } + + // Exception Handler + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex){ + return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); + } + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressRequestDTO.java new file mode 100644 index 0000000..6c217c1 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressRequestDTO.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AddressRequestDTO { + + @NotBlank(message = "Address is required") + private String address; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressResponseDTO.java new file mode 100644 index 0000000..2259b3e --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/AddressResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AddressResponseDTO { + + private Long addressId; + private Long userId; + private String address; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartRequestDTO.java new file mode 100644 index 0000000..5794ebc --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartRequestDTO.java @@ -0,0 +1,20 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CartRequestDTO { + + @NotNull(message = "Product ID is required") + private Long productId; + + @NotNull(message = "Quantity is required") + @Min(value = 1, message = "Quantity must be at least 1") + private Integer quantity; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartResponseDTO.java new file mode 100644 index 0000000..cc2b34b --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CartResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CartResponseDTO { + + private Long cartId; + private Long userId; + private Long productId; + private String productName; + private Integer quantity; + private LocalDateTime addedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectRequestDTO.java new file mode 100644 index 0000000..a743e24 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspectRequestDTO { + + @NotBlank(message = "Aspect๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String aspect; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectResponseDTO.java new file mode 100644 index 0000000..2d5b9fe --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryAspectResponseDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspectResponseDTO { + private Long id; + private String aspect; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryRequestDTO.java new file mode 100644 index 0000000..f9b24df --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryRequestDTO { + + @NotBlank(message = "์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryResponseDTO.java new file mode 100644 index 0000000..9e1bc16 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/CategoryResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryResponseDTO { + private Long categoryId; + private String name; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private List aspects; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionRequestDTO.java new file mode 100644 index 0000000..94de9aa --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionRequestDTO.java @@ -0,0 +1,29 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DescriptionRequestDTO { + + private String summaryExp; + private String summaryCook; + private String summaryStore; + private String cautionAllergy1; + private String cautionAllergy2; + private String cautionStore; + private String sizeDescription; + private String sizeImageUrl; + private String ingredient; + private String nutrition; + private String reviewGoodTaste; + private Integer reviewGoodTasteNum; + private String reviewGoodDelivery; + private Integer reviewGoodDeliveryNum; + private String reviewBadTaste; + private Integer reviewBadTasteNum; + private String reviewBadDelivery; + private Integer reviewBadDeliveryNum; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionResponseDTO.java new file mode 100644 index 0000000..d46ba5e --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/DescriptionResponseDTO.java @@ -0,0 +1,34 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DescriptionResponseDTO { + + private Long productId; + private String summaryExp; + private String summaryCook; + private String summaryStore; + private String cautionAllergy1; + private String cautionAllergy2; + private String cautionStore; + private String sizeDescription; + private String sizeImageUrl; + private String ingredient; + private String nutrition; + private String reviewGoodTaste; + private Integer reviewGoodTasteNum; + private String reviewGoodDelivery; + private Integer reviewGoodDeliveryNum; + private String reviewBadTaste; + private Integer reviewBadTasteNum; + private String reviewBadDelivery; + private Integer reviewBadDeliveryNum; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextRequestDTO.java new file mode 100644 index 0000000..9839c69 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextRequestDTO.java @@ -0,0 +1,11 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ImageToTextRequestDTO { + private String link; + private List images; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextResponseDTO.java new file mode 100644 index 0000000..8d39af9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ImageToTextResponseDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ImageToTextResponseDTO { + private Long id; + private String link; + private List images; + private List texts; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemRequestDTO.java new file mode 100644 index 0000000..60c7574 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemRequestDTO.java @@ -0,0 +1,24 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderItemRequestDTO { + + @NotNull(message = "Product ID is required") + private Long productId; + + @NotNull(message = "Quantity is required") + @Positive(message = "Quantity must be positive") + private Integer quantity; + + @NotNull(message = "Unit price is required") + @Positive(message = "Unit price must be positive") + private Integer unitPrice; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemResponseDTO.java new file mode 100644 index 0000000..0a0a10a --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderItemResponseDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderItemResponseDTO { + + private Long orderItemId; + private Long productId; + private String productName; + private Integer quantity; + private Integer unitPrice; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderRequestDTO.java new file mode 100644 index 0000000..4b92855 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderRequestDTO.java @@ -0,0 +1,31 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderRequestDTO { + + @NotNull(message = "Payment ID is required") + private Long paymentId; + + @NotNull(message = "Address ID is required") + private Long addressId; + + @NotBlank(message = "Order status is required") + private String orderStatus; + + @NotNull(message = "Total amount is required") + @Positive(message = "Total amount must be positive") + private Integer totalAmount; + + @NotNull(message = "Order items are required") + private List orderItems; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderResponseDTO.java new file mode 100644 index 0000000..26e883f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/OrderResponseDTO.java @@ -0,0 +1,23 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderResponseDTO { + + private Long orderId; + private Long userId; + private Long paymentId; + private Long addressId; + private String orderStatus; + private Integer totalAmount; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private List orderItems; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentRequestDTO.java new file mode 100644 index 0000000..dbd437f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentRequestDTO.java @@ -0,0 +1,21 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PaymentRequestDTO { + + @NotBlank(message = "Status is required") + private String status; + + @NotNull(message = "Payment amount is required") + @Min(value = 1, message = "Payment amount must be at least 1") + private Integer paymentAmount; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentResponseDTO.java new file mode 100644 index 0000000..ddc338f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/PaymentResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PaymentResponseDTO { + + private Long paymentId; + private Long userId; + private String status; + private Integer paymentAmount; + private LocalDateTime paymentDate; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankRequestDTO.java new file mode 100644 index 0000000..610abd5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRankRequestDTO { + private Integer productRankId; + private Integer productId; + private Integer aspectId; + private Integer categoryId; + private Integer productRank; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankResponseDTO.java new file mode 100644 index 0000000..2ef34cf --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRankResponseDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRankResponseDTO { + private Integer productRankId; + private Integer productId; + private Integer aspectId; + private Integer categoryId; + private Integer productRank; +} diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRequestDTO.java new file mode 100644 index 0000000..32441f9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductRequestDTO.java @@ -0,0 +1,38 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ProductRequestDTO { + + @NotNull(message = "์นดํ…Œ๊ณ ๋ฆฌ ID๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private Long categoryId; + + @NotBlank(message = "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; + + private String thumbnailUrl; + private String thumbnailCaption; + private String thumbnailCaptionShort; + private String mall; + + @Min(value = 0, message = "๊ฐ€๊ฒฉ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer price; + + @Min(value = 0, message = "์žฌ๊ณ ๋Š” 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer stock = 10; + + @Min(value = 0, message = "ํ‰์ ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Float rating; + + private String coupon; + private String delivery; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductResponseDTO.java new file mode 100644 index 0000000..792c5ef --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ProductResponseDTO.java @@ -0,0 +1,27 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ProductResponseDTO { + private Long productId; + private Long categoryId; + private String name; + private String thumbnailUrl; + private String thumbnailCaption; + private String thumbnailCaptionShort; + private String mall; + private Integer price; + private Integer stock; + private Float rating; + private String coupon; + private String delivery; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewRequestDTO.java new file mode 100644 index 0000000..fc7134a --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewRequestDTO.java @@ -0,0 +1,23 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReviewRequestDTO { + + @NotNull(message = "Rate is required") + @Min(value = 1, message = "Rate must be at least 1") + @Max(value = 5, message = "Rate must be at most 5") + private Integer rate; + + @NotBlank(message = "Comment is required") + private String comment; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewResponseDTO.java new file mode 100644 index 0000000..eb1ee6e --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/ReviewResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReviewResponseDTO { + + private Long reviewId; + private Long productId; + private Integer rate; + private String comment; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserRequestDTO.java new file mode 100644 index 0000000..711bfba --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserRequestDTO.java @@ -0,0 +1,21 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserRequestDTO { + + @Email(message = "์ด๋ฉ”์ผ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + @NotBlank(message = "์ด๋ฉ”์ผ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String email; + + @NotBlank(message = "์‚ฌ์šฉ์ž ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String username; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserResponseDTO.java new file mode 100644 index 0000000..6f902b4 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/controller/dto/UserResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.controller.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserResponseDTO { + private Long userId; + private String email; + private String username; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Address.java b/back/src/main/java/com/itsmenlp/foodly/entity/Address.java new file mode 100644 index 0000000..eb85947 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Address.java @@ -0,0 +1,44 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "ADDRESSES") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Address { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long addressId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @Column + private String address; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Cart.java b/back/src/main/java/com/itsmenlp/foodly/entity/Cart.java new file mode 100644 index 0000000..9a6bee6 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Cart.java @@ -0,0 +1,39 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "CARTS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Cart { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long cartId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @Column(nullable = false) + private Integer quantity = 1; + + @Column(nullable = false, updatable = false) + private LocalDateTime addedAt; + + @PrePersist + protected void onCreate() { + this.addedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Category.java b/back/src/main/java/com/itsmenlp/foodly/entity/Category.java new file mode 100644 index 0000000..a08a09b --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Category.java @@ -0,0 +1,49 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name = "CATEGORIES") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Category { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long categoryId; + + @Column(nullable = false, unique = true) + private String name; + + @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) + @Builder.Default + private List aspects = new ArrayList<>(); + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) + private List products; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/CategoryAspect.java b/back/src/main/java/com/itsmenlp/foodly/entity/CategoryAspect.java new file mode 100644 index 0000000..b67c498 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/CategoryAspect.java @@ -0,0 +1,25 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "CATEGORYASPECTS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspect { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "category_id", nullable = false) + private Category category; + + @Column(nullable = false) + private String aspect; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Description.java b/back/src/main/java/com/itsmenlp/foodly/entity/Description.java new file mode 100644 index 0000000..b52e55d --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Description.java @@ -0,0 +1,95 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "DESCRIPTIONS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Description { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long descriptionId; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @Column + private String summaryExp; + + @Column + private String summaryCook; + + @Column + private String summaryStore; + + @Column + private String cautionAllergy1; + + @Column + private String cautionAllergy2; + + @Column + private String cautionStore; + + @Column + private String sizeDescription; + + @Column + private String sizeImageUrl; + + @Column + private String ingredient; + + @Column + private String nutrition; + + @Column + private String reviewGoodTaste; + + @Column + private Integer reviewGoodTasteNum; + + @Column + private String reviewGoodDelivery; + + @Column + private Integer reviewGoodDeliveryNum; + + @Column + private String reviewBadTaste; + + @Column + private Integer reviewBadTasteNum; + + @Column + private String reviewBadDelivery; + + @Column + private Integer reviewBadDeliveryNum; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/ImageToText.java b/back/src/main/java/com/itsmenlp/foodly/entity/ImageToText.java new file mode 100644 index 0000000..653d802 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/ImageToText.java @@ -0,0 +1,33 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Entity +@Table(name = "image_to_text") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ImageToText { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // ์ž…๋ ฅ ๋ฐ์ดํ„ฐ + private String link; + + @ElementCollection + @CollectionTable(joinColumns = @JoinColumn(name = "image_to_text_id")) + @Column(name = "image_url") + private List inputImages; + + // ์™ธ๋ถ€ API์—์„œ ๋ฐ˜ํ™˜๋ฐ›์€ ๊ฒฐ๊ณผ + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(joinColumns = @JoinColumn(name = "image_to_text_id")) + @Column(name = "text", columnDefinition = "TEXT") + private List outputTexts; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Order.java b/back/src/main/java/com/itsmenlp/foodly/entity/Order.java new file mode 100644 index 0000000..734703f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Order.java @@ -0,0 +1,60 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name = "ORDERS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Order { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long orderId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "payment_id", nullable = false) + private Payment payment; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "address_id", nullable = false) + private Address address; + + @Column(nullable = false) + private String orderStatus; + + @Column(nullable = false) + private Integer totalAmount; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List orderItems = new ArrayList<>(); + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/OrderItem.java b/back/src/main/java/com/itsmenlp/foodly/entity/OrderItem.java new file mode 100644 index 0000000..9645ba9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/OrderItem.java @@ -0,0 +1,32 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "ORDERITEMS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderItem { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long orderItemId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "order_id") + private Order order; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @Column(nullable = false) + private Integer quantity; + + @Column(nullable = false) + private Integer unitPrice; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Payment.java b/back/src/main/java/com/itsmenlp/foodly/entity/Payment.java new file mode 100644 index 0000000..da9a3ae --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Payment.java @@ -0,0 +1,38 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "PAYMENTS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Payment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long paymentId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Column(nullable = false) + private String status; + + @Column(nullable = false) + private Integer paymentAmount; + + @Column(nullable = false, updatable = false) + private LocalDateTime paymentDate; + + @PrePersist + protected void onCreate() { + this.paymentDate = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Product.java b/back/src/main/java/com/itsmenlp/foodly/entity/Product.java new file mode 100644 index 0000000..1bc6561 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Product.java @@ -0,0 +1,71 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "PRODUCTS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Product { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long productId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; + + @Column(nullable = false) + private String name; + + @Column + private String thumbnailUrl; + + @Column(length=2000) + private String thumbnailCaption; + + @Column(length=2000) + private String thumbnailCaptionShort; + + @Column + private String mall; + + @Column + private Integer price; + + @Column(nullable = false) + private Integer stock = 10; + + @Column + private Float rating; + + @Column + private String coupon; + + @Column + private String delivery; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/ProductRank.java b/back/src/main/java/com/itsmenlp/foodly/entity/ProductRank.java new file mode 100644 index 0000000..47383d7 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/ProductRank.java @@ -0,0 +1,35 @@ +package com.itsmenlp.foodly.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.*; + +@Entity +@Table(name = "PRODUCTRANK") +@IdClass(ProductRankId.class) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRank { + + @Id + @Column + private Integer productRankId; + + @Id + @Column + private Integer productId; + + @Id + @Column + private Integer aspectId; + + @Id + @Column + private Integer categoryId; + + @Column + private Integer productRank; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/ProductRankId.java b/back/src/main/java/com/itsmenlp/foodly/entity/ProductRankId.java new file mode 100644 index 0000000..f2614a2 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/ProductRankId.java @@ -0,0 +1,17 @@ +package com.itsmenlp.foodly.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRankId implements Serializable { + private Integer productRankId; + private Integer productId; + private Integer aspectId; + private Integer categoryId; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/Review.java b/back/src/main/java/com/itsmenlp/foodly/entity/Review.java new file mode 100644 index 0000000..3decdda --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/Review.java @@ -0,0 +1,47 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "REVIEWS") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Review { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long reviewId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + + @Column + private Integer rate; + + @Column + private String comment; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/entity/User.java b/back/src/main/java/com/itsmenlp/foodly/entity/User.java new file mode 100644 index 0000000..b33a4e2 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/entity/User.java @@ -0,0 +1,45 @@ +package com.itsmenlp.foodly.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "USERS", uniqueConstraints = { + @UniqueConstraint(columnNames = "email"), +}) +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userId; + + @Column(nullable = false, unique = true) + private String email; + + @Column(nullable = false) + private String username; + + @Column(nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(nullable = false) + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } +} diff --git a/back/src/main/java/com/itsmenlp/foodly/exception/ResourceNotFoundException.java b/back/src/main/java/com/itsmenlp/foodly/exception/ResourceNotFoundException.java new file mode 100644 index 0000000..ee8910f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/exception/ResourceNotFoundException.java @@ -0,0 +1,7 @@ +package com.itsmenlp.foodly.exception; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/AddressRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/AddressRepository.java new file mode 100644 index 0000000..1ea4856 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/AddressRepository.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Address; +import com.itsmenlp.foodly.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AddressRepository extends JpaRepository { + + List
findByUser(User user); + boolean existsByAddressIdAndUser(Long addressId, User user); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/CartRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/CartRepository.java new file mode 100644 index 0000000..d2896c7 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/CartRepository.java @@ -0,0 +1,20 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Cart; +import com.itsmenlp.foodly.entity.Product; +import com.itsmenlp.foodly.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface CartRepository extends JpaRepository { + + List findByUser(User user); + + Optional findByCartIdAndUser(Long cartId, User user); + + boolean existsByProductAndUser(Product product, User user); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/CategoryAspectRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/CategoryAspectRepository.java new file mode 100644 index 0000000..c55149b --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/CategoryAspectRepository.java @@ -0,0 +1,10 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.CategoryAspect; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CategoryAspectRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/CategoryRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/CategoryRepository.java new file mode 100644 index 0000000..b41eb6a --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/CategoryRepository.java @@ -0,0 +1,12 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Category; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface CategoryRepository extends JpaRepository { + Optional findByName(String name); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/DescriptionRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/DescriptionRepository.java new file mode 100644 index 0000000..b906754 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/DescriptionRepository.java @@ -0,0 +1,10 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Description; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DescriptionRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/ImageToTextRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/ImageToTextRepository.java new file mode 100644 index 0000000..00d44e1 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/ImageToTextRepository.java @@ -0,0 +1,9 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.ImageToText; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ImageToTextRepository extends JpaRepository { +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/OrderItemRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/OrderItemRepository.java new file mode 100644 index 0000000..7c92fc5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/OrderItemRepository.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.OrderItem; +import com.itsmenlp.foodly.entity.Order; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface OrderItemRepository extends JpaRepository { + + List findByOrder(Order order); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/OrderRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/OrderRepository.java new file mode 100644 index 0000000..34f6ad0 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/OrderRepository.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Order; +import com.itsmenlp.foodly.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface OrderRepository extends JpaRepository { + + List findByUser(User user); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/PaymentRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/PaymentRepository.java new file mode 100644 index 0000000..4c597c0 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/PaymentRepository.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Payment; +import com.itsmenlp.foodly.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PaymentRepository extends JpaRepository { + + List findByUser(User user); + boolean existsByPaymentIdAndUser(Long paymentId, User user); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/ProductRankRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/ProductRankRepository.java new file mode 100644 index 0000000..ad6044b --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/ProductRankRepository.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.ProductRank; +import com.itsmenlp.foodly.entity.ProductRankId; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductRankRepository extends JpaRepository { + List findByAspectIdOrderByProductRankDesc(Integer aspectId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/ProductRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/ProductRepository.java new file mode 100644 index 0000000..03f0e79 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/ProductRepository.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Product; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductRepository extends JpaRepository { + List findByCategory_CategoryId(Long categoryId); + List findByNameContaining(String name); + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/ReviewRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/ReviewRepository.java new file mode 100644 index 0000000..8698a45 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/ReviewRepository.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.Review; +import com.itsmenlp.foodly.entity.Product; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ReviewRepository extends JpaRepository { + + List findByProduct(Product product); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/repository/UserRepository.java b/back/src/main/java/com/itsmenlp/foodly/repository/UserRepository.java new file mode 100644 index 0000000..9124a78 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/repository/UserRepository.java @@ -0,0 +1,12 @@ +package com.itsmenlp.foodly.repository; + +import com.itsmenlp.foodly.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface UserRepository extends JpaRepository { + Optional findByEmail(String email); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/AddressService.java b/back/src/main/java/com/itsmenlp/foodly/service/AddressService.java new file mode 100644 index 0000000..fc81d16 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/AddressService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.AddressServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.AddressServiceResponseDTO; + +import java.util.List; + +public interface AddressService { + + AddressServiceResponseDTO createAddress(Long userId, AddressServiceRequestDTO requestDTO); + List getAllAddresses(Long userId); + AddressServiceResponseDTO getAddressById(Long userId, Long addressId); + AddressServiceResponseDTO updateAddress(Long userId, Long addressId, AddressServiceRequestDTO requestDTO); + void deleteAddress(Long userId, Long addressId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/AddressServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/AddressServiceImpl.java new file mode 100644 index 0000000..3cb16e5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/AddressServiceImpl.java @@ -0,0 +1,101 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Address; +import com.itsmenlp.foodly.entity.User; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.AddressRepository; +import com.itsmenlp.foodly.repository.UserRepository; +import com.itsmenlp.foodly.service.dto.AddressServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.AddressServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class AddressServiceImpl implements AddressService { + + private final AddressRepository addressRepository; + private final UserRepository userRepository; + + @Override + @Transactional + public AddressServiceResponseDTO createAddress(Long userId, AddressServiceRequestDTO requestDTO) { + User user = getUserById(userId); + + Address address = Address.builder() + .user(user) + .address(requestDTO.getAddress()) + .build(); + + Address savedAddress = addressRepository.save(address); + + return mapToServiceResponseDTO(savedAddress); + } + + @Override + @Transactional(readOnly = true) + public List getAllAddresses(Long userId) { + User user = getUserById(userId); + List
addresses = addressRepository.findByUser(user); + + return addresses.stream() + .map(this::mapToServiceResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public AddressServiceResponseDTO getAddressById(Long userId, Long addressId) { + User user = getUserById(userId); + Address address = getAddressByIdAndUser(addressId, user); + + return mapToServiceResponseDTO(address); + } + + @Override + @Transactional + public AddressServiceResponseDTO updateAddress(Long userId, Long addressId, AddressServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Address address = getAddressByIdAndUser(addressId, user); + + address.setAddress(requestDTO.getAddress()); + + Address updatedAddress = addressRepository.save(address); + + return mapToServiceResponseDTO(updatedAddress); + } + + @Override + @Transactional + public void deleteAddress(Long userId, Long addressId) { + User user = getUserById(userId); + Address address = getAddressByIdAndUser(addressId, user); + + addressRepository.delete(address); + } + + private User getUserById(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId)); + } + + private Address getAddressByIdAndUser(Long addressId, User user) { + return addressRepository.findById(addressId) + .filter(address -> address.getUser().equals(user)) + .orElseThrow(() -> new ResourceNotFoundException("Address not found with id: " + addressId + " for user id: " + user.getUserId())); + } + + private AddressServiceResponseDTO mapToServiceResponseDTO(Address address) { + return AddressServiceResponseDTO.builder() + .addressId(address.getAddressId()) + .userId(address.getUser().getUserId()) + .address(address.getAddress()) + .createdAt(address.getCreatedAt()) + .updatedAt(address.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CartService.java b/back/src/main/java/com/itsmenlp/foodly/service/CartService.java new file mode 100644 index 0000000..9f0b935 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CartService.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.CartServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.CartServiceResponseDTO; + +import java.util.List; + +public interface CartService { + + CartServiceResponseDTO addProductToCart(Long userId, CartServiceRequestDTO requestDTO); + + List getAllCartItems(Long userId); + + CartServiceResponseDTO getCartItemById(Long userId, Long cartId); + + CartServiceResponseDTO updateCartItem(Long userId, Long cartId, CartServiceRequestDTO requestDTO); + + void removeCartItem(Long userId, Long cartId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CartServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/CartServiceImpl.java new file mode 100644 index 0000000..8082e90 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CartServiceImpl.java @@ -0,0 +1,127 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Cart; +import com.itsmenlp.foodly.entity.Product; +import com.itsmenlp.foodly.entity.User; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.CartRepository; +import com.itsmenlp.foodly.repository.ProductRepository; +import com.itsmenlp.foodly.repository.UserRepository; +import com.itsmenlp.foodly.service.dto.CartServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.CartServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class CartServiceImpl implements CartService { + + private final CartRepository cartRepository; + private final UserRepository userRepository; + private final ProductRepository productRepository; + + @Override + @Transactional + public CartServiceResponseDTO addProductToCart(Long userId, CartServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Product product = getProductById(requestDTO.getProductId()); + + // ์œ ์ €์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ด๋ฏธ ํ•ด๋‹น ์ƒํ’ˆ์ด ์žˆ๋Š”์ง€ ํ™•์ธ + boolean exists = cartRepository.existsByProductAndUser(product, user); + if (exists) { + throw new IllegalArgumentException("Product already exists in the cart."); + } + + Cart cart = Cart.builder() + .user(user) + .product(product) + .quantity(requestDTO.getQuantity()) + .build(); + + Cart savedCart = cartRepository.save(cart); + + return mapToServiceResponseDTO(savedCart); + } + + @Override + @Transactional(readOnly = true) + public List getAllCartItems(Long userId) { + User user = getUserById(userId); + List carts = cartRepository.findByUser(user); + + return carts.stream() + .map(this::mapToServiceResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public CartServiceResponseDTO getCartItemById(Long userId, Long cartId) { + User user = getUserById(userId); + Cart cart = getCartByIdAndUser(cartId, user); + + return mapToServiceResponseDTO(cart); + } + + @Override + @Transactional + public CartServiceResponseDTO updateCartItem(Long userId, Long cartId, CartServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Cart cart = getCartByIdAndUser(cartId, user); + + // ์—…๋ฐ์ดํŠธํ•  ์ƒํ’ˆ์ด ๋‹ค๋ฅธ ์ƒํ’ˆ์ผ ๊ฒฝ์šฐ ์ค‘๋ณต ํ™•์ธ + if (!cart.getProduct().getProductId().equals(requestDTO.getProductId())) { + Product newProduct = getProductById(requestDTO.getProductId()); + boolean exists = cartRepository.existsByProductAndUser(newProduct, user); + if (exists) { + throw new IllegalArgumentException("Product already exists in the cart."); + } + cart.setProduct(newProduct); + } + + cart.setQuantity(requestDTO.getQuantity()); + + Cart updatedCart = cartRepository.save(cart); + + return mapToServiceResponseDTO(updatedCart); + } + + @Override + @Transactional + public void removeCartItem(Long userId, Long cartId) { + User user = getUserById(userId); + Cart cart = getCartByIdAndUser(cartId, user); + + cartRepository.delete(cart); + } + + private User getUserById(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId)); + } + + private Product getProductById(Long productId) { + return productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + productId)); + } + + private Cart getCartByIdAndUser(Long cartId, User user) { + return cartRepository.findByCartIdAndUser(cartId, user) + .orElseThrow(() -> new ResourceNotFoundException("Cart not found with id: " + cartId + " for user id: " + user.getUserId())); + } + + private CartServiceResponseDTO mapToServiceResponseDTO(Cart cart) { + return CartServiceResponseDTO.builder() + .cartId(cart.getCartId()) + .userId(cart.getUser().getUserId()) + .productId(cart.getProduct().getProductId()) + .productName(cart.getProduct().getName()) + .quantity(cart.getQuantity()) + .addedAt(cart.getAddedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectService.java b/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectService.java new file mode 100644 index 0000000..a105738 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.CategoryAspectCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectUpdateRequestDTO; + +import java.util.List; + +public interface CategoryAspectService { + CategoryAspectServiceResponseDTO createAspect(Long categoryId, CategoryAspectCreateRequestDTO dto); + CategoryAspectServiceResponseDTO getAspectById(Long aspectId); + List getAllAspectsByCategory(Long categoryId); + CategoryAspectServiceResponseDTO updateAspect(Long aspectId, CategoryAspectUpdateRequestDTO dto); + void deleteAspect(Long aspectId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectServiceImpl.java new file mode 100644 index 0000000..12cb0b8 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CategoryAspectServiceImpl.java @@ -0,0 +1,87 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Category; +import com.itsmenlp.foodly.entity.CategoryAspect; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.CategoryAspectRepository; +import com.itsmenlp.foodly.repository.CategoryRepository; +import com.itsmenlp.foodly.service.dto.CategoryAspectCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryAspectUpdateRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class CategoryAspectServiceImpl implements CategoryAspectService { + + private final CategoryAspectRepository aspectRepository; + private final CategoryRepository categoryRepository; + + @Autowired + public CategoryAspectServiceImpl(CategoryAspectRepository aspectRepository, CategoryRepository categoryRepository) { + this.aspectRepository = aspectRepository; + this.categoryRepository = categoryRepository; + } + + @Override + public CategoryAspectServiceResponseDTO createAspect(Long categoryId, CategoryAspectCreateRequestDTO dto) { + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + categoryId)); + + CategoryAspect aspect = CategoryAspect.builder() + .aspect(dto.getAspect()) + .category(category) + .build(); + + CategoryAspect savedAspect = aspectRepository.save(aspect); + return mapToResponseDTO(savedAspect); + } + + @Override + @Transactional(readOnly = true) + public CategoryAspectServiceResponseDTO getAspectById(Long aspectId) { + CategoryAspect aspect = aspectRepository.findById(aspectId) + .orElseThrow(() -> new ResourceNotFoundException("Aspect not found with id " + aspectId)); + return mapToResponseDTO(aspect); + } + + @Override + @Transactional(readOnly = true) + public List getAllAspectsByCategory(Long categoryId) { + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + categoryId)); + + return category.getAspects().stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + @Override + public CategoryAspectServiceResponseDTO updateAspect(Long aspectId, CategoryAspectUpdateRequestDTO dto) { + CategoryAspect aspect = aspectRepository.findById(aspectId) + .orElseThrow(() -> new ResourceNotFoundException("Aspect not found with id " + aspectId)); + aspect.setAspect(dto.getAspect()); + CategoryAspect updatedAspect = aspectRepository.save(aspect); + return mapToResponseDTO(updatedAspect); + } + + @Override + public void deleteAspect(Long aspectId) { + if (!aspectRepository.existsById(aspectId)) { + throw new ResourceNotFoundException("Aspect not found with id " + aspectId); + } + aspectRepository.deleteById(aspectId); + } + + private CategoryAspectServiceResponseDTO mapToResponseDTO(CategoryAspect aspect) { + return CategoryAspectServiceResponseDTO.builder() + .id(aspect.getId()) + .aspect(aspect.getAspect()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CategoryService.java b/back/src/main/java/com/itsmenlp/foodly/service/CategoryService.java new file mode 100644 index 0000000..f4a0734 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CategoryService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.CategoryCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryUpdateRequestDTO; + +import java.util.List; + +public interface CategoryService { + CategoryServiceResponseDTO createCategory(CategoryCreateRequestDTO dto); + CategoryServiceResponseDTO getCategoryById(Long categoryId); + List getAllCategories(); + CategoryServiceResponseDTO updateCategory(Long categoryId, CategoryUpdateRequestDTO dto); + void deleteCategory(Long categoryId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/CategoryServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/CategoryServiceImpl.java new file mode 100644 index 0000000..1c2cd25 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/CategoryServiceImpl.java @@ -0,0 +1,87 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Category; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.CategoryRepository; +import com.itsmenlp.foodly.service.dto.CategoryAspectServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.CategoryServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.CategoryUpdateRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class CategoryServiceImpl implements CategoryService { + + private final CategoryRepository categoryRepository; + + @Autowired + public CategoryServiceImpl(CategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; + } + + @Override + public CategoryServiceResponseDTO createCategory(CategoryCreateRequestDTO dto) { + Category category = Category.builder() + .name(dto.getName()) + .build(); + Category savedCategory = categoryRepository.save(category); + return mapToResponseDTO(savedCategory); + } + + @Override + @Transactional(readOnly = true) + public CategoryServiceResponseDTO getCategoryById(Long categoryId) { + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + categoryId)); + return mapToResponseDTO(category); + } + + @Override + @Transactional(readOnly = true) + public List getAllCategories() { + List categories = categoryRepository.findAll(); + return categories.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + @Override + public CategoryServiceResponseDTO updateCategory(Long categoryId, CategoryUpdateRequestDTO dto) { + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + categoryId)); + category.setName(dto.getName()); + Category updatedCategory = categoryRepository.save(category); + return mapToResponseDTO(updatedCategory); + } + + @Override + public void deleteCategory(Long categoryId) { + if (!categoryRepository.existsById(categoryId)) { + throw new ResourceNotFoundException("Category not found with id " + categoryId); + } + categoryRepository.deleteById(categoryId); + } + + private CategoryServiceResponseDTO mapToResponseDTO(Category category) { + List aspectDTOs = category.getAspects().stream() + .map(aspect -> CategoryAspectServiceResponseDTO.builder() + .id(aspect.getId()) + .aspect(aspect.getAspect()) + .build()) + .collect(Collectors.toList()); + + return CategoryServiceResponseDTO.builder() + .categoryId(category.getCategoryId()) + .name(category.getName()) + .createdAt(category.getCreatedAt()) + .updatedAt(category.getUpdatedAt()) + .aspects(aspectDTOs) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/DescriptionService.java b/back/src/main/java/com/itsmenlp/foodly/service/DescriptionService.java new file mode 100644 index 0000000..b8f7d4f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/DescriptionService.java @@ -0,0 +1,12 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.DescriptionServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.DescriptionServiceResponseDTO; + +public interface DescriptionService { + + DescriptionServiceResponseDTO createDescription(Long productId, DescriptionServiceRequestDTO requestDTO); + DescriptionServiceResponseDTO getDescription(Long productId); + DescriptionServiceResponseDTO updateDescription(Long productId, DescriptionServiceRequestDTO requestDTO); + void deleteDescription(Long productId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/DescriptionServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/DescriptionServiceImpl.java new file mode 100644 index 0000000..e590ab5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/DescriptionServiceImpl.java @@ -0,0 +1,132 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Description; +import com.itsmenlp.foodly.entity.Product; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.DescriptionRepository; +import com.itsmenlp.foodly.repository.ProductRepository; +import com.itsmenlp.foodly.service.dto.DescriptionServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.DescriptionServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class DescriptionServiceImpl implements DescriptionService { + + private final DescriptionRepository descriptionRepository; + private final ProductRepository productRepository; + + @Override + @Transactional + public DescriptionServiceResponseDTO createDescription(Long productId, DescriptionServiceRequestDTO requestDTO) { + // ์ƒํ’ˆ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ + Product product = productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + productId)); + + // Description์ด ์ด๋ฏธ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ + if (descriptionRepository.existsById(productId)) { + throw new IllegalArgumentException("Description already exists for product id: " + productId); + } + + // Description ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ + Description description = Description.builder() + .product(product) + .summaryExp(requestDTO.getSummaryExp()) + .summaryCook(requestDTO.getSummaryCook()) + .summaryStore(requestDTO.getSummaryStore()) + .cautionAllergy1(requestDTO.getCautionAllergy1()) + .cautionAllergy2(requestDTO.getCautionAllergy2()) + .cautionStore(requestDTO.getCautionStore()) + .sizeDescription(requestDTO.getSizeDescription()) + .sizeImageUrl(requestDTO.getSizeImageUrl()) + .ingredient(requestDTO.getIngredient()) + .nutrition(requestDTO.getNutrition()) + .reviewGoodTaste(requestDTO.getReviewGoodTaste()) + .reviewGoodTasteNum(requestDTO.getReviewGoodTasteNum()) + .reviewGoodDelivery(requestDTO.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(requestDTO.getReviewGoodDeliveryNum()) + .reviewBadTaste(requestDTO.getReviewBadTaste()) + .reviewBadTasteNum(requestDTO.getReviewBadTasteNum()) + .reviewBadDelivery(requestDTO.getReviewBadDelivery()) + .reviewBadDeliveryNum(requestDTO.getReviewBadDeliveryNum()) + .build(); + + Description savedDescription = descriptionRepository.save(description); + + return mapToServiceResponseDTO(savedDescription); + } + + @Override + @Transactional(readOnly = true) + public DescriptionServiceResponseDTO getDescription(Long productId) { + Description description = descriptionRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Description not found for product id: " + productId)); + return mapToServiceResponseDTO(description); + } + + @Override + @Transactional + public DescriptionServiceResponseDTO updateDescription(Long productId, DescriptionServiceRequestDTO requestDTO) { + Description description = descriptionRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Description not found for product id: " + productId)); + + description.setSummaryExp(requestDTO.getSummaryExp()); + description.setSummaryCook(requestDTO.getSummaryCook()); + description.setSummaryStore(requestDTO.getSummaryStore()); + description.setCautionAllergy1(requestDTO.getCautionAllergy1()); + description.setCautionAllergy2(requestDTO.getCautionAllergy2()); + description.setCautionStore(requestDTO.getCautionStore()); + description.setSizeDescription(requestDTO.getSizeDescription()); + description.setSizeImageUrl(requestDTO.getSizeImageUrl()); + description.setNutrition(requestDTO.getNutrition()); + description.setIngredient(requestDTO.getIngredient()); + description.setReviewGoodTaste(requestDTO.getReviewGoodTaste()); + description.setReviewGoodTasteNum(requestDTO.getReviewGoodTasteNum()); + description.setReviewGoodDelivery(requestDTO.getReviewGoodDelivery()); + description.setReviewGoodDeliveryNum(requestDTO.getReviewGoodDeliveryNum()); + description.setReviewBadTaste(requestDTO.getReviewBadTaste()); + description.setReviewBadTasteNum(requestDTO.getReviewBadTasteNum()); + description.setReviewBadDelivery(requestDTO.getReviewBadDelivery()); + description.setReviewBadDeliveryNum(requestDTO.getReviewBadDeliveryNum()); + + Description updatedDescription = descriptionRepository.save(description); + + return mapToServiceResponseDTO(updatedDescription); + } + + @Override + @Transactional + public void deleteDescription(Long productId) { + Description description = descriptionRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Description not found for product id: " + productId)); + descriptionRepository.delete(description); + } + + private DescriptionServiceResponseDTO mapToServiceResponseDTO(Description description) { + return DescriptionServiceResponseDTO.builder() + .productId(description.getProduct().getProductId()) + .summaryExp(description.getSummaryExp()) + .summaryCook(description.getSummaryCook()) + .summaryStore(description.getSummaryStore()) + .cautionAllergy1(description.getCautionAllergy1()) + .cautionAllergy2(description.getCautionAllergy2()) + .cautionStore(description.getCautionStore()) + .sizeDescription(description.getSizeDescription()) + .sizeImageUrl(description.getSizeImageUrl()) + .nutrition(description.getNutrition()) + .ingredient(description.getIngredient()) + .reviewGoodTaste(description.getReviewGoodTaste()) + .reviewGoodTasteNum(description.getReviewGoodTasteNum()) + .reviewGoodDelivery(description.getReviewGoodDelivery()) + .reviewGoodDeliveryNum(description.getReviewGoodDeliveryNum()) + .reviewBadTaste(description.getReviewBadTaste()) + .reviewBadTasteNum(description.getReviewBadTasteNum()) + .reviewBadDelivery(description.getReviewBadDelivery()) + .reviewBadDeliveryNum(description.getReviewBadDeliveryNum()) + .createdAt(description.getCreatedAt()) + .updatedAt(description.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextService.java b/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextService.java new file mode 100644 index 0000000..ee5e173 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextService.java @@ -0,0 +1,11 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.ImageToTextServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ImageToTextServiceResponseDTO; +import org.springframework.stereotype.Service; + +@Service +public interface ImageToTextService { + ImageToTextServiceResponseDTO processInput(ImageToTextServiceRequestDTO serviceRequest); + +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextServiceImpl.java new file mode 100644 index 0000000..818f731 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ImageToTextServiceImpl.java @@ -0,0 +1,62 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.ImageToText; +import com.itsmenlp.foodly.repository.ImageToTextRepository; +import com.itsmenlp.foodly.service.dto.ImageToTextServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ImageToTextServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.ProcessImageToTextResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +@RequiredArgsConstructor +public class ImageToTextServiceImpl implements ImageToTextService { + + private final ImageToTextRepository imageToTextRepository; + private final RestTemplate restTemplate; + + @Override + public ImageToTextServiceResponseDTO processInput(ImageToTextServiceRequestDTO serviceRequest) { + // 1. ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ + ImageToText entity = new ImageToText(); + entity.setLink(serviceRequest.getLink()); + entity.setInputImages(serviceRequest.getImages()); + ImageToText savedEntity = imageToTextRepository.save(entity); + + // 2. ์™ธ๋ถ€ API ํ˜ธ์ถœ + String externalApiUrl = "http://127.0.0.1:5001/process"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + // ์™ธ๋ถ€ API ์š”์ฒญ์‹œ serviceRequest์˜ ๊ตฌ์กฐ(์˜ˆ, link์™€ images)๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ • + HttpEntity requestEntity = new HttpEntity<>(serviceRequest, headers); + ResponseEntity responseEntity = restTemplate.postForEntity( + externalApiUrl, + requestEntity, + ProcessImageToTextResponseDTO.class + ); + + ProcessImageToTextResponseDTO externalResponse = responseEntity.getBody(); + if (externalResponse == null || externalResponse.getTexts() == null) { + throw new RuntimeException("Invalid response from external API"); + } + + // 3. ์™ธ๋ถ€ API๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ texts๋ฅผ ์—”ํ‹ฐํ‹ฐ์— ์—…๋ฐ์ดํŠธ ํ›„ ์ €์žฅ + savedEntity.setOutputTexts(externalResponse.getTexts()); + imageToTextRepository.save(savedEntity); + + // 4. ์„œ๋น„์Šค ์‘๋‹ต DTO๋กœ ๋ณ€ํ™˜ + ImageToTextServiceResponseDTO serviceResponse = new ImageToTextServiceResponseDTO(); + serviceResponse.setId(savedEntity.getId()); + serviceResponse.setLink(savedEntity.getLink()); + serviceResponse.setInputImages(savedEntity.getInputImages()); + serviceResponse.setOutputTexts(savedEntity.getOutputTexts()); + return serviceResponse; + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/OrderService.java b/back/src/main/java/com/itsmenlp/foodly/service/OrderService.java new file mode 100644 index 0000000..dd1a3e6 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/OrderService.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.OrderServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.OrderServiceResponseDTO; + +import java.util.List; + +public interface OrderService { + + OrderServiceResponseDTO createOrder(Long userId, OrderServiceRequestDTO requestDTO); + + List getAllOrders(Long userId); + + OrderServiceResponseDTO getOrderById(Long userId, Long orderId); + + OrderServiceResponseDTO updateOrder(Long userId, Long orderId, OrderServiceRequestDTO requestDTO); + + void deleteOrder(Long userId, Long orderId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/OrderServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/OrderServiceImpl.java new file mode 100644 index 0000000..53da077 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/OrderServiceImpl.java @@ -0,0 +1,185 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.*; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.*; +import com.itsmenlp.foodly.service.dto.*; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class OrderServiceImpl implements OrderService { + + private final OrderRepository orderRepository; + private final OrderItemRepository orderItemRepository; + private final UserRepository userRepository; + private final PaymentRepository paymentRepository; + private final AddressRepository addressRepository; + private final ProductRepository productRepository; + private final CartRepository cartRepository; + + @Override + @Transactional + public OrderServiceResponseDTO createOrder(Long userId, OrderServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Payment payment = getPaymentByIdAndUser(requestDTO.getPaymentId(), user); + Address address = getAddressByIdAndUser(requestDTO.getAddressId(), user); + + Order order = Order.builder() + .user(user) + .payment(payment) + .address(address) + .orderStatus(requestDTO.getOrderStatus()) + .totalAmount(requestDTO.getTotalAmount()) + .build(); + + Order savedOrder = orderRepository.save(order); + + List orderItemsDTO = requestDTO.getOrderItems(); + + List orderItems = orderItemsDTO.stream() + .map(itemDTO -> { + Product product = getProductById(itemDTO.getProductId()); + return OrderItem.builder() + .order(savedOrder) + .product(product) + .quantity(itemDTO.getQuantity()) + .unitPrice(itemDTO.getUnitPrice()) + .build(); + }) + .collect(Collectors.toList()); + + orderItemRepository.saveAll(orderItems); + + savedOrder.setOrderItems(orderItems); + + return mapToServiceResponseDTO(savedOrder); + } + + @Override + @Transactional(readOnly = true) + public List getAllOrders(Long userId) { + User user = getUserById(userId); + List orders = orderRepository.findByUser(user); + + return orders.stream() + .map(this::mapToServiceResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public OrderServiceResponseDTO getOrderById(Long userId, Long orderId) { + User user = getUserById(userId); + Order order = getOrderByIdAndUser(orderId, user); + + return mapToServiceResponseDTO(order); + } + + @Override + @Transactional + public OrderServiceResponseDTO updateOrder(Long userId, Long orderId, OrderServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Order order = getOrderByIdAndUser(orderId, user); + + Payment payment = getPaymentByIdAndUser(requestDTO.getPaymentId(), user); + Address address = getAddressByIdAndUser(requestDTO.getAddressId(), user); + + order.setPayment(payment); + order.setAddress(address); + order.setOrderStatus(requestDTO.getOrderStatus()); + order.setTotalAmount(requestDTO.getTotalAmount()); + + // ๊ธฐ์กด ์ฃผ๋ฌธ ํ•ญ๋ชฉ ์‚ญ์ œ + orderItemRepository.deleteAll(order.getOrderItems()); + + // ์ƒˆ๋กœ์šด ์ฃผ๋ฌธ ํ•ญ๋ชฉ ์ถ”๊ฐ€ + List orderItemsDTO = requestDTO.getOrderItems(); + + List orderItems = orderItemsDTO.stream() + .map(itemDTO -> { + Product product = getProductById(itemDTO.getProductId()); + return OrderItem.builder() + .order(order) + .product(product) + .quantity(itemDTO.getQuantity()) + .unitPrice(itemDTO.getUnitPrice()) + .build(); + }) + .collect(Collectors.toList()); + + orderItemRepository.saveAll(orderItems); + + order.setOrderItems(orderItems); + + Order updatedOrder = orderRepository.save(order); + + return mapToServiceResponseDTO(updatedOrder); + } + + @Override + @Transactional + public void deleteOrder(Long userId, Long orderId) { + User user = getUserById(userId); + Order order = getOrderByIdAndUser(orderId, user); + + orderRepository.delete(order); + } + + private User getUserById(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId)); + } + + private Payment getPaymentByIdAndUser(Long paymentId, User user) { + return paymentRepository.findById(paymentId) + .filter(payment -> payment.getUser().equals(user)) + .orElseThrow(() -> new ResourceNotFoundException("Payment not found with id: " + paymentId + " for user id: " + user.getUserId())); + } + + private Address getAddressByIdAndUser(Long addressId, User user) { + return addressRepository.findById(addressId) + .filter(address -> address.getUser().equals(user)) + .orElseThrow(() -> new ResourceNotFoundException("Address not found with id: " + addressId + " for user id: " + user.getUserId())); + } + + private Product getProductById(Long productId) { + return productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + productId)); + } + + private Order getOrderByIdAndUser(Long orderId, User user) { + return orderRepository.findById(orderId) + .filter(order -> order.getUser().equals(user)) + .orElseThrow(() -> new ResourceNotFoundException("Order not found with id: " + orderId + " for user id: " + user.getUserId())); + } + + private OrderServiceResponseDTO mapToServiceResponseDTO(Order order) { + List orderItemsDTO = order.getOrderItems().stream() + .map(item -> OrderItemServiceResponseDTO.builder() + .orderItemId(item.getOrderItemId()) + .productId(item.getProduct().getProductId()) + .productName(item.getProduct().getName()) + .quantity(item.getQuantity()) + .unitPrice(item.getUnitPrice()) + .build()) + .collect(Collectors.toList()); + + return OrderServiceResponseDTO.builder() + .orderId(order.getOrderId()) + .userId(order.getUser().getUserId()) + .paymentId(order.getPayment().getPaymentId()) + .addressId(order.getAddress().getAddressId()) + .orderStatus(order.getOrderStatus()) + .totalAmount(order.getTotalAmount()) + .createdAt(order.getCreatedAt()) + .updatedAt(order.getUpdatedAt()) + .orderItems(orderItemsDTO) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/PaymentService.java b/back/src/main/java/com/itsmenlp/foodly/service/PaymentService.java new file mode 100644 index 0000000..6a72ba8 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/PaymentService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.PaymentServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.PaymentServiceResponseDTO; + +import java.util.List; + +public interface PaymentService { + + PaymentServiceResponseDTO createPayment(Long userId, PaymentServiceRequestDTO requestDTO); + List getAllPayments(Long userId); + PaymentServiceResponseDTO getPaymentById(Long userId, Long paymentId); + PaymentServiceResponseDTO updatePayment(Long userId, Long paymentId, PaymentServiceRequestDTO requestDTO); + void deletePayment(Long userId, Long paymentId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/PaymentServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/PaymentServiceImpl.java new file mode 100644 index 0000000..7d2af14 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/PaymentServiceImpl.java @@ -0,0 +1,103 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Payment; +import com.itsmenlp.foodly.entity.User; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.PaymentRepository; +import com.itsmenlp.foodly.repository.UserRepository; +import com.itsmenlp.foodly.service.dto.PaymentServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.PaymentServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class PaymentServiceImpl implements PaymentService { + + private final PaymentRepository paymentRepository; + private final UserRepository userRepository; + + @Override + @Transactional + public PaymentServiceResponseDTO createPayment(Long userId, PaymentServiceRequestDTO requestDTO) { + User user = getUserById(userId); + + Payment payment = Payment.builder() + .user(user) + .status(requestDTO.getStatus()) + .paymentAmount(requestDTO.getPaymentAmount()) + .build(); + + Payment savedPayment = paymentRepository.save(payment); + + return mapToServiceResponseDTO(savedPayment); + } + + @Override + @Transactional(readOnly = true) + public List getAllPayments(Long userId) { + User user = getUserById(userId); + List payments = paymentRepository.findByUser(user); + + return payments.stream() + .map(this::mapToServiceResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public PaymentServiceResponseDTO getPaymentById(Long userId, Long paymentId) { + User user = getUserById(userId); + Payment payment = getPaymentByIdAndUser(paymentId, user); + + return mapToServiceResponseDTO(payment); + } + + @Override + @Transactional + public PaymentServiceResponseDTO updatePayment(Long userId, Long paymentId, PaymentServiceRequestDTO requestDTO) { + User user = getUserById(userId); + Payment payment = getPaymentByIdAndUser(paymentId, user); + + payment.setStatus(requestDTO.getStatus()); + payment.setPaymentAmount(requestDTO.getPaymentAmount()); + + Payment updatedPayment = paymentRepository.save(payment); + + return mapToServiceResponseDTO(updatedPayment); + } + + @Override + @Transactional + public void deletePayment(Long userId, Long paymentId) { + User user = getUserById(userId); + Payment payment = getPaymentByIdAndUser(paymentId, user); + + paymentRepository.delete(payment); + } + + private User getUserById(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId)); + } + + private Payment getPaymentByIdAndUser(Long paymentId, User user) { + return paymentRepository.findById(paymentId) + .filter(payment -> payment.getUser().equals(user)) + .orElseThrow(() -> new ResourceNotFoundException("Payment not found with id: " + paymentId + " for user id: " + user.getUserId())); + } + + private PaymentServiceResponseDTO mapToServiceResponseDTO(Payment payment) { + return PaymentServiceResponseDTO.builder() + .paymentId(payment.getPaymentId()) + .userId(payment.getUser().getUserId()) + .status(payment.getStatus()) + .paymentAmount(payment.getPaymentAmount()) + .paymentDate(payment.getPaymentDate()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ProductRankService.java b/back/src/main/java/com/itsmenlp/foodly/service/ProductRankService.java new file mode 100644 index 0000000..b174acc --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ProductRankService.java @@ -0,0 +1,23 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.ProductRank; +import com.itsmenlp.foodly.entity.ProductRankId; +import com.itsmenlp.foodly.repository.ProductRankRepository; +import com.itsmenlp.foodly.service.dto.ProductRankRequestDTO; +import com.itsmenlp.foodly.service.dto.ProductRankResponseDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public interface ProductRankService { + ProductRankResponseDTO createProductRank(ProductRankRequestDTO requestDto); + ProductRankResponseDTO getProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId); + ProductRankResponseDTO updateProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId, ProductRankRequestDTO requestDto); + void deleteProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId); + + List getAllProductRanks(); + List getProductRanksByAspect(Integer aspectId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ProductRankServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/ProductRankServiceImpl.java new file mode 100644 index 0000000..f57b9f2 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ProductRankServiceImpl.java @@ -0,0 +1,84 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.ProductRank; +import com.itsmenlp.foodly.entity.ProductRankId; +import com.itsmenlp.foodly.repository.ProductRankRepository; +import com.itsmenlp.foodly.service.dto.ProductRankRequestDTO; +import com.itsmenlp.foodly.service.dto.ProductRankResponseDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ProductRankServiceImpl implements ProductRankService { + + private final ProductRankRepository productRankRepository; + + public ProductRankServiceImpl(ProductRankRepository productRankRepository) { + this.productRankRepository = productRankRepository; + } + + // ์—”ํ‹ฐํ‹ฐ -> DTO ๋ณ€ํ™˜ + private ProductRankResponseDTO convertToDto(ProductRank productRank) { + return new ProductRankResponseDTO( + productRank.getProductRankId(), + productRank.getProductId(), + productRank.getAspectId(), + productRank.getCategoryId(), + productRank.getProductRank() + ); + } + + // ๋“ฑ๋ก (Create) + public ProductRankResponseDTO createProductRank(ProductRankRequestDTO requestDto) { + ProductRank productRank = new ProductRank( + requestDto.getProductRankId(), + requestDto.getProductId(), + requestDto.getAspectId(), + requestDto.getCategoryId(), + requestDto.getProductRank() + ); + ProductRank saved = productRankRepository.save(productRank); + return convertToDto(saved); + } + + // ๋‹จ๊ฑด ์กฐํšŒ (Read) + public ProductRankResponseDTO getProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId) { + ProductRankId id = new ProductRankId(productRankId, productId, aspectId, categoryId); + ProductRank productRank = productRankRepository.findById(id) + .orElseThrow(() -> new RuntimeException("ProductRank not found")); + return convertToDto(productRank); + } + + // ์ˆ˜์ • (Update) + public ProductRankResponseDTO updateProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId, ProductRankRequestDTO requestDto) { + ProductRankId id = new ProductRankId(productRankId, productId, aspectId, categoryId); + ProductRank productRank = productRankRepository.findById(id) + .orElseThrow(() -> new RuntimeException("ProductRank not found")); + productRank.setProductRank(requestDto.getProductRank()); + ProductRank updated = productRankRepository.save(productRank); + return convertToDto(updated); + } + + // ์‚ญ์ œ (Delete) + public void deleteProductRank(Integer productRankId, Integer productId, Integer aspectId, Integer categoryId) { + ProductRankId id = new ProductRankId(productRankId, productId, aspectId, categoryId); + productRankRepository.deleteById(id); + } + + // ์ „์ฒด ๋ชฉ๋ก ์กฐํšŒ + public List getAllProductRanks() { + return productRankRepository.findAll() + .stream() + .map(this::convertToDto) + .collect(Collectors.toList()); + } + + // ํŠน์ • aspect_id์˜ ๋ฐ์ดํ„ฐ๋ฅผ rank(=COUNT) ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ์กฐํšŒ + public List getProductRanksByAspect(Integer aspectId) { + List list = productRankRepository.findByAspectIdOrderByProductRankDesc(aspectId); + return list.stream().map(this::convertToDto).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ProductService.java b/back/src/main/java/com/itsmenlp/foodly/service/ProductService.java new file mode 100644 index 0000000..af4afd9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ProductService.java @@ -0,0 +1,17 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.ProductCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.ProductServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.ProductUpdateRequestDTO; + +import java.util.List; + +public interface ProductService { + ProductServiceResponseDTO createProduct(ProductCreateRequestDTO dto); + ProductServiceResponseDTO getProductById(Long productId); + List getAllProducts(); + List getProductsByCategoryId(Long categoryId); + ProductServiceResponseDTO updateProduct(Long productId, ProductUpdateRequestDTO dto); + void deleteProduct(Long productId); + List getProductsByName(String name); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ProductServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/ProductServiceImpl.java new file mode 100644 index 0000000..5dc99bb --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ProductServiceImpl.java @@ -0,0 +1,139 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Category; +import com.itsmenlp.foodly.entity.Product; +import com.itsmenlp.foodly.repository.CategoryRepository; +import com.itsmenlp.foodly.repository.ProductRepository; +import com.itsmenlp.foodly.service.dto.ProductCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.ProductServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.ProductUpdateRequestDTO; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class ProductServiceImpl implements ProductService { + + private final ProductRepository productRepository; + private final CategoryRepository categoryRepository; + + @Autowired + public ProductServiceImpl(ProductRepository productRepository, CategoryRepository categoryRepository) { + this.productRepository = productRepository; + this.categoryRepository = categoryRepository; + } + + @Override + public ProductServiceResponseDTO createProduct(ProductCreateRequestDTO dto) { + Category category = categoryRepository.findById(dto.getCategoryId()) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + dto.getCategoryId())); + + Product product = Product.builder() + .category(category) + .name(dto.getName()) + .thumbnailUrl(dto.getThumbnailUrl()) + .thumbnailCaption(dto.getThumbnailCaption()) + .thumbnailCaptionShort(dto.getThumbnailCaptionShort()) + .mall(dto.getMall()) + .price(dto.getPrice()) + .stock(dto.getStock() != null ? dto.getStock() : 10) + .rating(dto.getRating()) + .coupon(dto.getCoupon()) + .delivery(dto.getDelivery()) + .build(); + + Product savedProduct = productRepository.save(product); + return mapToResponseDTO(savedProduct); + } + + @Override + @Transactional(readOnly = true) + public ProductServiceResponseDTO getProductById(Long productId) { + Product product = productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id " + productId)); + return mapToResponseDTO(product); + } + + @Override + @Transactional(readOnly = true) + public List getAllProducts() { + List products = productRepository.findAll(); + return products.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public List getProductsByCategoryId(Long categoryId) { + List products = productRepository.findByCategory_CategoryId(categoryId); + return products.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + @Override + public ProductServiceResponseDTO updateProduct(Long productId, ProductUpdateRequestDTO dto) { + Product product = productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id " + productId)); + + Category category = categoryRepository.findById(dto.getCategoryId()) + .orElseThrow(() -> new ResourceNotFoundException("Category not found with id " + dto.getCategoryId())); + + product.setCategory(category); + product.setName(dto.getName()); + product.setThumbnailUrl(dto.getThumbnailUrl()); + product.setThumbnailCaption(dto.getThumbnailCaption()); + product.setThumbnailCaptionShort(dto.getThumbnailCaptionShort()); + product.setMall(dto.getMall()); + product.setPrice(dto.getPrice()); + product.setStock(dto.getStock() != null ? dto.getStock() : product.getStock()); + product.setRating(dto.getRating()); + product.setCoupon(dto.getCoupon()); + product.setDelivery(dto.getDelivery()); + + Product updatedProduct = productRepository.save(product); + return mapToResponseDTO(updatedProduct); + } + + @Override + public void deleteProduct(Long productId) { + if (!productRepository.existsById(productId)) { + throw new ResourceNotFoundException("Product not found with id " + productId); + } + productRepository.deleteById(productId); + } + + @Override + @Transactional(readOnly = true) + public List getProductsByName(String name) { + List products = productRepository.findByNameContaining(name); + return products.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + private ProductServiceResponseDTO mapToResponseDTO(Product product) { + return ProductServiceResponseDTO.builder() + .productId(product.getProductId()) + .categoryId(product.getCategory() != null ? product.getCategory().getCategoryId() : null) + .name(product.getName()) + .thumbnailUrl(product.getThumbnailUrl()) + .thumbnailCaption(product.getThumbnailCaption()) + .thumbnailCaptionShort(product.getThumbnailCaptionShort()) + .mall(product.getMall()) + .price(product.getPrice()) + .stock(product.getStock()) + .rating(product.getRating()) + .coupon(product.getCoupon()) + .delivery(product.getDelivery()) + .createdAt(product.getCreatedAt()) + .updatedAt(product.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/RestTemplateConfig.java b/back/src/main/java/com/itsmenlp/foodly/service/RestTemplateConfig.java new file mode 100644 index 0000000..98993b8 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/RestTemplateConfig.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.service; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ReviewService.java b/back/src/main/java/com/itsmenlp/foodly/service/ReviewService.java new file mode 100644 index 0000000..bf86b08 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ReviewService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.ReviewServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ReviewServiceResponseDTO; + +import java.util.List; + +public interface ReviewService { + + ReviewServiceResponseDTO createReview(Long productId, ReviewServiceRequestDTO requestDTO); + List getAllReviews(Long productId); + ReviewServiceResponseDTO getReviewById(Long productId, Long reviewId); + ReviewServiceResponseDTO updateReview(Long productId, Long reviewId, ReviewServiceRequestDTO requestDTO); + void deleteReview(Long productId, Long reviewId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/ReviewServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/ReviewServiceImpl.java new file mode 100644 index 0000000..38e798a --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/ReviewServiceImpl.java @@ -0,0 +1,104 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.Product; +import com.itsmenlp.foodly.entity.Review; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.ProductRepository; +import com.itsmenlp.foodly.repository.ReviewRepository; +import com.itsmenlp.foodly.service.dto.ReviewServiceRequestDTO; +import com.itsmenlp.foodly.service.dto.ReviewServiceResponseDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ReviewServiceImpl implements ReviewService { + + private final ReviewRepository reviewRepository; + private final ProductRepository productRepository; + + @Override + @Transactional + public ReviewServiceResponseDTO createReview(Long productId, ReviewServiceRequestDTO requestDTO) { + Product product = getProductById(productId); + + Review review = Review.builder() + .product(product) + .rate(requestDTO.getRate()) + .comment(requestDTO.getComment()) + .build(); + + Review savedReview = reviewRepository.save(review); + + return mapToServiceResponseDTO(savedReview); + } + + @Override + @Transactional(readOnly = true) + public List getAllReviews(Long productId) { + Product product = getProductById(productId); + List reviews = reviewRepository.findByProduct(product); + + return reviews.stream() + .map(this::mapToServiceResponseDTO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public ReviewServiceResponseDTO getReviewById(Long productId, Long reviewId) { + Product product = getProductById(productId); + Review review = getReviewByIdAndProduct(reviewId, product); + + return mapToServiceResponseDTO(review); + } + + @Override + @Transactional + public ReviewServiceResponseDTO updateReview(Long productId, Long reviewId, ReviewServiceRequestDTO requestDTO) { + Product product = getProductById(productId); + Review review = getReviewByIdAndProduct(reviewId, product); + + review.setRate(requestDTO.getRate()); + review.setComment(requestDTO.getComment()); + + Review updatedReview = reviewRepository.save(review); + + return mapToServiceResponseDTO(updatedReview); + } + + @Override + @Transactional + public void deleteReview(Long productId, Long reviewId) { + Product product = getProductById(productId); + Review review = getReviewByIdAndProduct(reviewId, product); + + reviewRepository.delete(review); + } + + private Product getProductById(Long productId) { + return productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + productId)); + } + + private Review getReviewByIdAndProduct(Long reviewId, Product product) { + return reviewRepository.findById(reviewId) + .filter(review -> review.getProduct().equals(product)) + .orElseThrow(() -> new ResourceNotFoundException("Review not found with id: " + reviewId + " for product id: " + product.getProductId())); + } + + private ReviewServiceResponseDTO mapToServiceResponseDTO(Review review) { + return ReviewServiceResponseDTO.builder() + .reviewId(review.getReviewId()) + .productId(review.getProduct().getProductId()) + .rate(review.getRate()) + .comment(review.getComment()) + .createdAt(review.getCreatedAt()) + .updatedAt(review.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/UserService.java b/back/src/main/java/com/itsmenlp/foodly/service/UserService.java new file mode 100644 index 0000000..68fb093 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/UserService.java @@ -0,0 +1,15 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.service.dto.UserCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.UserServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.UserUpdateRequestDTO; + +import java.util.List; + +public interface UserService { + UserServiceResponseDTO createUser(UserCreateRequestDTO userCreateRequestDTO); + UserServiceResponseDTO getUserById(Long userId); + List getAllUsers(); + UserServiceResponseDTO updateUser(Long userId, UserUpdateRequestDTO userUpdateRequestDTO); + void deleteUser(Long userId); +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/UserServiceImpl.java b/back/src/main/java/com/itsmenlp/foodly/service/UserServiceImpl.java new file mode 100644 index 0000000..8194915 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/UserServiceImpl.java @@ -0,0 +1,80 @@ +package com.itsmenlp.foodly.service; + +import com.itsmenlp.foodly.entity.User; +import com.itsmenlp.foodly.exception.ResourceNotFoundException; +import com.itsmenlp.foodly.repository.UserRepository; +import com.itsmenlp.foodly.service.dto.UserCreateRequestDTO; +import com.itsmenlp.foodly.service.dto.UserServiceResponseDTO; +import com.itsmenlp.foodly.service.dto.UserUpdateRequestDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + + @Autowired + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public UserServiceResponseDTO createUser(UserCreateRequestDTO dto) { + User user = User.builder() + .email(dto.getEmail()) + .username(dto.getUsername()) + .build(); + User savedUser = userRepository.save(user); + return mapToResponseDTO(savedUser); + } + + @Override + @Transactional(readOnly = true) + public UserServiceResponseDTO getUserById(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id " + userId)); + return mapToResponseDTO(user); + } + + @Override + @Transactional(readOnly = true) + public List getAllUsers() { + List users = userRepository.findAll(); + return users.stream() + .map(this::mapToResponseDTO) + .collect(Collectors.toList()); + } + + @Override + public UserServiceResponseDTO updateUser(Long userId, UserUpdateRequestDTO dto) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("User not found with id " + userId)); + user.setUsername(dto.getUsername()); + User updatedUser = userRepository.save(user); + return mapToResponseDTO(updatedUser); + } + + @Override + public void deleteUser(Long userId) { + if(!userRepository.existsById(userId)) { + throw new ResourceNotFoundException("User not found with id " + userId); + } + userRepository.deleteById(userId); + } + + private UserServiceResponseDTO mapToResponseDTO(User user) { + return UserServiceResponseDTO.builder() + .userId(user.getUserId()) + .email(user.getEmail()) + .username(user.getUsername()) + .createdAt(user.getCreatedAt()) + .updatedAt(user.getUpdatedAt()) + .build(); + } +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceRequestDTO.java new file mode 100644 index 0000000..3eec432 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceRequestDTO.java @@ -0,0 +1,12 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AddressServiceRequestDTO { + + private String address; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceResponseDTO.java new file mode 100644 index 0000000..132d5e1 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/AddressServiceResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AddressServiceResponseDTO { + + private Long addressId; + private Long userId; + private String address; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceRequestDTO.java new file mode 100644 index 0000000..e06dc59 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceRequestDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CartServiceRequestDTO { + + private Long productId; + private Integer quantity; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceResponseDTO.java new file mode 100644 index 0000000..f73a6eb --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CartServiceResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CartServiceResponseDTO { + + private Long cartId; + private Long userId; + private Long productId; + private String productName; + private Integer quantity; + private LocalDateTime addedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectCreateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectCreateRequestDTO.java new file mode 100644 index 0000000..26d0436 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectCreateRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspectCreateRequestDTO { + + @NotBlank(message = "Aspect๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String aspect; +} diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectServiceResponseDTO.java new file mode 100644 index 0000000..c4396a7 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectServiceResponseDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspectServiceResponseDTO { + private Long id; + private String aspect; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectUpdateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectUpdateRequestDTO.java new file mode 100644 index 0000000..67bb2e0 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryAspectUpdateRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryAspectUpdateRequestDTO { + + @NotBlank(message = "Aspect๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String aspect; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryCreateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryCreateRequestDTO.java new file mode 100644 index 0000000..d961212 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryCreateRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryCreateRequestDTO { + + @NotBlank(message = "์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryServiceResponseDTO.java new file mode 100644 index 0000000..b6f689f --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryServiceResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryServiceResponseDTO { + private Long categoryId; + private String name; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private List aspects; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryUpdateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryUpdateRequestDTO.java new file mode 100644 index 0000000..d506429 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/CategoryUpdateRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CategoryUpdateRequestDTO { + + @NotBlank(message = "์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceRequestDTO.java new file mode 100644 index 0000000..e77c79b --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceRequestDTO.java @@ -0,0 +1,29 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DescriptionServiceRequestDTO { + + private String summaryExp; + private String summaryCook; + private String summaryStore; + private String cautionAllergy1; + private String cautionAllergy2; + private String cautionStore; + private String sizeDescription; + private String sizeImageUrl; + private String ingredient; + private String nutrition; + private String reviewGoodTaste; + private Integer reviewGoodTasteNum; + private String reviewGoodDelivery; + private Integer reviewGoodDeliveryNum; + private String reviewBadTaste; + private Integer reviewBadTasteNum; + private String reviewBadDelivery; + private Integer reviewBadDeliveryNum; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceResponseDTO.java new file mode 100644 index 0000000..7d6be2a --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/DescriptionServiceResponseDTO.java @@ -0,0 +1,34 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DescriptionServiceResponseDTO { + + private Long productId; + private String summaryExp; + private String summaryCook; + private String summaryStore; + private String cautionAllergy1; + private String cautionAllergy2; + private String cautionStore; + private String sizeDescription; + private String sizeImageUrl; + private String ingredient; + private String nutrition; + private String reviewGoodTaste; + private Integer reviewGoodTasteNum; + private String reviewGoodDelivery; + private Integer reviewGoodDeliveryNum; + private String reviewBadTaste; + private Integer reviewBadTasteNum; + private String reviewBadDelivery; + private Integer reviewBadDeliveryNum; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceRequestDTO.java new file mode 100644 index 0000000..e80e9f4 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceRequestDTO.java @@ -0,0 +1,11 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ImageToTextServiceRequestDTO { + private String link; + private List images; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceResponseDTO.java new file mode 100644 index 0000000..10fcdd7 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ImageToTextServiceResponseDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ImageToTextServiceResponseDTO { + private Long id; + private String link; + private List inputImages; + private List outputTexts; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceRequestDTO.java new file mode 100644 index 0000000..3689559 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceRequestDTO.java @@ -0,0 +1,14 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderItemServiceRequestDTO { + + private Long productId; + private Integer quantity; + private Integer unitPrice; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceResponseDTO.java new file mode 100644 index 0000000..ae133ab --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderItemServiceResponseDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderItemServiceResponseDTO { + + private Long orderItemId; + private Long productId; + private String productName; + private Integer quantity; + private Integer unitPrice; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceRequestDTO.java new file mode 100644 index 0000000..c1b1ba9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceRequestDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderServiceRequestDTO { + + private Long paymentId; + private Long addressId; + private String orderStatus; + private Integer totalAmount; + private List orderItems; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceResponseDTO.java new file mode 100644 index 0000000..91c5ef0 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/OrderServiceResponseDTO.java @@ -0,0 +1,23 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class OrderServiceResponseDTO { + + private Long orderId; + private Long userId; + private Long paymentId; + private Long addressId; + private String orderStatus; + private Integer totalAmount; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private List orderItems; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceRequestDTO.java new file mode 100644 index 0000000..965f4e5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceRequestDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PaymentServiceRequestDTO { + + private String status; + private Integer paymentAmount; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceResponseDTO.java new file mode 100644 index 0000000..38da27d --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/PaymentServiceResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PaymentServiceResponseDTO { + + private Long paymentId; + private Long userId; + private String status; + private Integer paymentAmount; + private LocalDateTime paymentDate; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProcessImageToTextResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProcessImageToTextResponseDTO.java new file mode 100644 index 0000000..0716184 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProcessImageToTextResponseDTO.java @@ -0,0 +1,10 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ProcessImageToTextResponseDTO { + private List texts; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductCreateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductCreateRequestDTO.java new file mode 100644 index 0000000..73e04e5 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductCreateRequestDTO.java @@ -0,0 +1,38 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ProductCreateRequestDTO { + + @NotNull(message = "์นดํ…Œ๊ณ ๋ฆฌ ID๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private Long categoryId; + + @NotBlank(message = "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; + + private String thumbnailUrl; + private String thumbnailCaption; + private String thumbnailCaptionShort; + private String mall; + + @Min(value = 0, message = "๊ฐ€๊ฒฉ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer price; + + @Min(value = 0, message = "์žฌ๊ณ ๋Š” 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer stock = 10; + + @Min(value = 0, message = "ํ‰์ ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Float rating; + + private String coupon; + private String delivery; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankRequestDTO.java new file mode 100644 index 0000000..71a92f9 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRankRequestDTO { + private Integer productRankId; + private Integer productId; + private Integer aspectId; + private Integer categoryId; + private Integer productRank; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankResponseDTO.java new file mode 100644 index 0000000..a284685 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductRankResponseDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductRankResponseDTO { + private Integer productRankId; + private Integer productId; + private Integer aspectId; + private Integer categoryId; + private Integer productRank; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductServiceResponseDTO.java new file mode 100644 index 0000000..cba863e --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductServiceResponseDTO.java @@ -0,0 +1,27 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ProductServiceResponseDTO { + private Long productId; + private Long categoryId; + private String name; + private String thumbnailUrl; + private String thumbnailCaption; + private String thumbnailCaptionShort; + private String mall; + private Integer price; + private Integer stock; + private Float rating; + private String coupon; + private String delivery; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductUpdateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductUpdateRequestDTO.java new file mode 100644 index 0000000..d6472a0 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ProductUpdateRequestDTO.java @@ -0,0 +1,38 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ProductUpdateRequestDTO { + + @NotNull(message = "์นดํ…Œ๊ณ ๋ฆฌ ID๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private Long categoryId; + + @NotBlank(message = "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String name; + + private String thumbnailUrl; + private String thumbnailCaption; + private String thumbnailCaptionShort; + private String mall; + + @Min(value = 0, message = "๊ฐ€๊ฒฉ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer price; + + @Min(value = 0, message = "์žฌ๊ณ ๋Š” 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Integer stock; + + @Min(value = 0, message = "ํ‰์ ์€ 0 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + private Float rating; + + private String coupon; + private String delivery; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceRequestDTO.java new file mode 100644 index 0000000..f216266 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceRequestDTO.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReviewServiceRequestDTO { + + private Integer rate; + private String comment; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceResponseDTO.java new file mode 100644 index 0000000..8a29a3d --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/ReviewServiceResponseDTO.java @@ -0,0 +1,19 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReviewServiceResponseDTO { + + private Long reviewId; + private Long productId; + private Integer rate; + private String comment; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/UserCreateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserCreateRequestDTO.java new file mode 100644 index 0000000..2f7dc02 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserCreateRequestDTO.java @@ -0,0 +1,21 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserCreateRequestDTO { + + @Email(message = "์ด๋ฉ”์ผ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + @NotBlank(message = "์ด๋ฉ”์ผ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String email; + + @NotBlank(message = "์‚ฌ์šฉ์ž ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String username; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/UserServiceResponseDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserServiceResponseDTO.java new file mode 100644 index 0000000..37671b4 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserServiceResponseDTO.java @@ -0,0 +1,18 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserServiceResponseDTO { + private Long userId; + private String email; + private String username; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/back/src/main/java/com/itsmenlp/foodly/service/dto/UserUpdateRequestDTO.java b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserUpdateRequestDTO.java new file mode 100644 index 0000000..a164e16 --- /dev/null +++ b/back/src/main/java/com/itsmenlp/foodly/service/dto/UserUpdateRequestDTO.java @@ -0,0 +1,16 @@ +package com.itsmenlp.foodly.service.dto; + +import lombok.*; + +import jakarta.validation.constraints.NotBlank; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserUpdateRequestDTO { + + @NotBlank(message = "์‚ฌ์šฉ์ž ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") + private String username; +} \ No newline at end of file diff --git a/back/src/main/resources/application.properties b/back/src/main/resources/application.properties new file mode 100644 index 0000000..e416f52 --- /dev/null +++ b/back/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.application.name=foodly +spring.datasource.url=${SPRING_DATASOURCE_URL} +spring.datasource.username=${SPRING_DATASOURCE_USERNAME} +spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} +spring.jpa.generate-ddl=true +spring.jpa.hibernate.ddl-auto=update + +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect \ No newline at end of file diff --git a/back/src/test/java/com/itsmenlp/foodly/FoodlyApplicationTests.java b/back/src/test/java/com/itsmenlp/foodly/FoodlyApplicationTests.java new file mode 100644 index 0000000..b5f47ce --- /dev/null +++ b/back/src/test/java/com/itsmenlp/foodly/FoodlyApplicationTests.java @@ -0,0 +1,13 @@ +package com.itsmenlp.foodly; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +//@SpringBootTest +class FoodlyApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/doc/Foodly_Presentation.pdf b/doc/Foodly_Presentation.pdf new file mode 100644 index 0000000..23e1b9b Binary files /dev/null and b/doc/Foodly_Presentation.pdf differ diff --git a/doc/Foodly_Wrap-Up_Report.pdf b/doc/Foodly_Wrap-Up_Report.pdf new file mode 100644 index 0000000..7e317ea Binary files /dev/null and b/doc/Foodly_Wrap-Up_Report.pdf differ diff --git a/doc/image/demo.mp4 b/doc/image/demo.mp4 new file mode 100644 index 0000000..33f634c Binary files /dev/null and b/doc/image/demo.mp4 differ diff --git a/doc/image/foodly_timeline.png b/doc/image/foodly_timeline.png new file mode 100644 index 0000000..3f230a8 Binary files /dev/null and b/doc/image/foodly_timeline.png differ diff --git a/doc/image/github_dark.png b/doc/image/github_dark.png new file mode 100644 index 0000000..10b895f Binary files /dev/null and b/doc/image/github_dark.png differ diff --git a/doc/image/github_light.png b/doc/image/github_light.png new file mode 100644 index 0000000..d66bdeb Binary files /dev/null and b/doc/image/github_light.png differ diff --git a/eda/README.md b/eda/README.md new file mode 100644 index 0000000..d8de25e --- /dev/null +++ b/eda/README.md @@ -0,0 +1,49 @@ +# ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ๋ฐ EDA + +- ๋„ค์ด๋ฒ„ ์‡ผํ•‘ > ์žฅ๋ณด๊ธฐํƒญ > ์ฃผ์š” ์‡ผํ•‘๋ชฐ์˜ ์‹๋ฃŒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•ด์„œ EDA ์ˆ˜ํ–‰ +- EDA ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํ”„๋กœ์ ํŠธ์— ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ, ๋ฐ์ดํ„ฐ๋ณ„ AI ๊ธฐ์ˆ  ๋งค์นญ ๊ฐ€์ด๋“œ ๊ตฌ์ถ• + +## ์ฃผ์š” ํŠน์ง• + +- **๋ฐ์ดํ„ฐ ์ˆ˜์ง‘:** + `product_crawling.py`๋ฅผ ์ด์šฉํ•ด์„œ ๋„ค์ด๋ฒ„ ์‡ผํ•‘์˜ ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ƒํ’ˆ URL, ์ด๋ฆ„, ๋งˆ์ผ“, ์นดํ…Œ๊ณ ๋ฆฌ ๋“ฑ ๊ธฐ๋ณธ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ , ๊ฐ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ์ธ๋„ค์ผ, ๊ฐ€๊ฒฉ, ๋ณ„์ , ์ƒ์„ธ ์ด๋ฏธ์ง€ ๋ฐ ํ…์ŠคํŠธ, ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ถ”์ถœ + +- **EDA ์ˆ˜ํ–‰:** + ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ + - `eda1_visualize.ipynb`: 1์ฐจ EDA๋ฅผ ํ†ตํ•ด ๊ฐ ๋งˆ์ผ“๋ณ„ ์ •๋ณด ์ œ๊ณต ๋ฐฉ์‹๊ณผ ํ˜•ํƒœ๋ฅผ ํŒŒ์•… + - `eda2_visualization.ipynb`: 2์ฐจ EDA๋ฅผ ํ†ตํ•ด ์ƒํ’ˆ ์ƒ์„ธ ์„ค๋ช…์˜ ์ •ํ˜•ํ™” ์—ฌ๋ถ€ ๋ฐ ์„œ๋น„์Šค ๊ฐœ๋ฐœ์„ ์œ„ํ•œ AI ๊ธฐ์ˆ  ๋งค์นญ ๊ฐ€์ด๋“œ๋ฅผ ๋„์ถœ + +- **ํŒŒ์ดํ”„๋ผ์ธ ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ์…‹ ๊ตฌ์ถ•:** + - ํฌ๋กค๋ง๊ณผ EDA ๊ฒฐ๊ณผ๋ฅผ ํ™œ์šฉํ•ด์„œ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ ํ•ต์‹ฌ ํŒŒ์ดํ”„๋ผ์ธ์— ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ๋ฐ์ดํ„ฐ์…‹์„ ์™„์„ฑ + +## ํด๋” ๊ตฌ์กฐ +```bash +. +โ”œโ”€โ”€ product_crawling.py # ๋ฐ์ดํ„ฐ ํฌ๋กค๋ง ๋ฐ ์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด ์ถ”์ถœ ์Šคํฌ๋ฆฝํŠธ +โ”œโ”€โ”€ eda1_visualize.ipynb # 1์ฐจ EDA ๋ฐ ์‹œ๊ฐํ™” ๋…ธํŠธ๋ถ +โ”œโ”€โ”€ eda2_visualization.ipynb # 2์ฐจ EDA ๋ฐ ์‹œ๊ฐํ™” ๋…ธํŠธ๋ถ +โ””โ”€โ”€ README.md # ํ”„๋กœ์ ํŠธ ๋ฌธ์„œ +``` + +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• + +1. **ํŒจํ‚ค์ง€ ์„ค์น˜** + ```bash + pip install ipywidgets webdriver-manager beautifulsoup4 selenium tqdm + ``` + +2. **๋ฐ์ดํ„ฐ ์ˆ˜์ง‘** + ```bash + python product_crawling.py + ``` + +3. **EDA** + - Google Sheets๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ˆ˜๋™ ๋ ˆ์ด๋ธ”๋ง ๊ฒ€์ˆ˜๊ฐ€ ์™„๋ฃŒ๋œ `.csv` ํŒŒ์ผ ํ•„์š” + - eda1_visualize.ipynb: 1์ฐจ EDA์™€ ๊ธฐ๋ณธ ์‹œ๊ฐํ™” ๊ฒฐ๊ณผ ํ™•์ธ + - eda2_visualization.ipynb: 2์ฐจ EDA๋ฅผ ํ†ตํ•œ ์ •ํ˜•ํ™” ์—ฌ๋ถ€ ํ™•์ธ ๋ฐ AI ๊ธฐ์ˆ  ๋งค์นญ ๊ฐ€์ด๋“œ ๋„์ถœ + +## ์ถ”๊ฐ€ ์ •๋ณด +- **๋™์  ํŽ˜์ด์ง€ ๋กœ๋”ฉ:** + ํฌ๋กค๋ง ๊ณผ์ •์—์„œ ํŽ˜์ด์ง€ ์Šคํฌ๋กค๊ณผ ๋™์  ๋กœ๋”ฉ์„ ๊ณ ๋ คํ–ˆ์œผ๋ฏ€๋กœ, ๋„ค์ด๋ฒ„ ์‡ผํ•‘ ํŽ˜์ด์ง€ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์‹œ ์ฝ”๋“œ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ +- **ํ–ฅํ›„ ๊ณ„ํš:** + EDA ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์˜จ๋ผ์ธ ์‡ผํ•‘ ์ ‘๊ทผ์„ฑ ๊ฐœ์„  ๋ฐ AI ๊ธฐ์ˆ  ์ ์šฉ์— ๊ด€ํ•œ ๊ตฌ์ฒด์ ์ธ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ฐœ๋ฐœ ์˜ˆ์ • diff --git a/eda/eda1_visualize.ipynb b/eda/eda1_visualize.ipynb new file mode 100644 index 0000000..b215684 --- /dev/null +++ b/eda/eda1_visualize.ipynb @@ -0,0 +1,389 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EDA ๋Œ€์ƒ\n", + "- ๋„๋ฉ”์ธ: ๋„ค์ด๋ฒ„ ์‡ผํ•‘์˜ ์žฅ๋ณด๊ธฐ ํƒญ\n", + "- ์‡ผํ•‘๋ชฐ: `์ด๋งˆํŠธ๋ชฐ`, `์ด๋งˆํŠธ ์—๋ธŒ๋ฆฌ๋ฐ์ด`, `ํ™ˆํ”Œ๋Ÿฌ์Šค`, `GS THE FRESH`\n", + "\n", + "
\n", + "\n", + "### ํ™•์ธํ•ด์•ผ ํ•  ์š”์†Œ\n", + "- ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜: ์ƒํ’ˆ๋ณ„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ด๋ฏธ์ง€์˜ ๊ฐœ์ˆ˜์˜ ํ‰๊ท \n", + "- ๊ตฌ๋ถ„ ๋‹จ์œ„(img + txt): ์ด๋ฏธ์ง€ ๋‚ด ํ…์ŠคํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, OCR ๋ฐ VLM ํ•„์š” ์—ฌ๋ถ€ ํŒŒ์•…\n", + "- ์ด๋ฏธ์ง€-ํ…์ŠคํŠธ ๊ตฌ์„ฑ: ์ด๋ฏธ์ง€ ์™ธ ํ…์ŠคํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ •๋ณด์˜ ํ˜•ํƒœ ํŒŒ์•…\n", + "- ์„ฑ๋ถ„ ์ •๋ณด: ์ œ๊ณต ํ˜•ํƒœ(์ด๋ฏธ์ง€, ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€+ํ…์ŠคํŠธ, ์ œ๊ณต ์•ˆ ํ•จ)\n", + "- ์„ฑ๋ถ„ ํ‘œ๊ธฐ ๊ฐ€๋…์„ฑ: ์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ์— ์„ ๋ช…, ํ๋ฆผ, ๊นจ์ง ํŒŒ์•…\n", + "- ๋ณด๊ด€ ์ •๋ณด: ์ด๋ฏธ์ง€, ํ…์ŠคํŠธ, ์ œ๊ณต ์•ˆ ํ•จ\n", + "- ๊ตํ™˜/๋ฐ˜ํ’ˆ ์ •๋ณด: ์ด๋ฏธ์ง€, ํ…์ŠคํŠธ, ์ œ๊ณต ์•ˆ ํ•จ\n", + "- ๋ฐฐ์†ก ์ •๋ณด: ์ด๋ฏธ์ง€, ํ…์ŠคํŠธ, ์ œ๊ณต ์•ˆ ํ•จ" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "emarteveryday: ์ƒํ’ˆ 599๊ฐœ, ํ‰๊ท  ์ด๋ฏธ์ง€ 2.29๊ฐœ\n", + "homeplus: ์ƒํ’ˆ 600๊ฐœ, ํ‰๊ท  ์ด๋ฏธ์ง€ 3.59๊ฐœ\n", + "emart: ์ƒํ’ˆ 1242๊ฐœ, ํ‰๊ท  ์ด๋ฏธ์ง€ 3.84๊ฐœ\n", + "gsthefresh: ์ƒํ’ˆ 651๊ฐœ, ํ‰๊ท  ์ด๋ฏธ์ง€ 2.49๊ฐœ\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "from matplotlib import rc\n", + "import matplotlib.pyplot as plt\n", + "\n", + "rc(\"font\", family=\"AppleGothic\")\n", + "plt.rcParams[\"axes.unicode_minus\"] = False\n", + "seaborn_color = sns.color_palette(\"pastel\") # Set2, pastel\n", + "\n", + "total_df = pd.read_csv(\"eda1.csv\").dropna(subset=[\"idx\"])\n", + "malls = list(set([id_.split(\"-\")[0] for id_ in total_df[\"idx\"].to_list()]))\n", + "\n", + "for mall in malls:\n", + " num = total_df[\"idx\"].str.contains(mall).sum()\n", + " num_img = int(total_df.loc[total_df[\"idx\"].str.contains(mall), \"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\"].sum())\n", + " print(f\"{mall}: ์ƒํ’ˆ {num}๊ฐœ, ํ‰๊ท  ์ด๋ฏธ์ง€ {round(num_img/num, 2)}๊ฐœ\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๊ตฌ๋ถ„ ๋‹จ์œ„\n", + "- ์ด๋ฏธ์ง€ ๋‚ด ํ…์ŠคํŠธ ์กด์žฌ ์—ฌ๋ถ€ ํŒŒ์•…\n", + "- OCR+LLM, VLM ์‚ฌ์šฉ ์—ฌ๋ถ€ ํŒŒ์•…" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB9sAAAH/CAYAAAD38r1XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAg3xJREFUeJzs3Qm4VVX5OODFJCIzKuI8YIhT5UA5pKmRiUOkaKCpoGnmlCZKklNaDiU5z0po4ozmUL9wQi2HFKdERcnUQFQUlVHBgft/vtX/3O4IHLzTufd9n2fHPfvss88+N+/51l7fWt9qVVZWVpYAAAAAAAAAgKXWeukPBQAAAAAAAACCZDsAAAAAAAAAFEmyHQAAAAAAAACKJNkOAAAAAAAAAEWSbAcAAAAAAACAIkm2AwAAAAAAAECRJNsBAAAAAAAAoEiS7QAAAAAAAABQJMl2AAAAAAAAACiSZDvAUnjggQdSq1at0sMPP9zYlwJAC/Hmm2+2qNizww47pGHDhjX2ZQAAAEBJ3eNPmTIl31N37tw5rb766undd99NDenaa6/Nnw1aqraNfQEAAAAAAABA8QYNGpQ+/fTTdPHFF6fPP/88tW/fvrEvCVoUM9uBosQItRipBgAAAFCRPgMASLlqW8w0bwgfffRRevHFF9MZZ5yR3/eQQw5J3bt3b5D3Bv5Lsh0AAAAAAABKzJw5c/K/q6yySmNfCrRYku0AAAAAAABQYsrKyhr7EqDFk2yHRrRw4cJ09tlnp4022igtv/zyabXVVktHHnlkLv0SovTaSiutlNdZOeecc9IGG2yQVlhhhXx8rL+yaNGifNwf//jHtNlmm6UOHTqkddddN5133nnV3uuWW25J/fv3T926dcvvFcfffPPNNZZ8+/Of/5yuuuqq1KdPn9SmTZt07LHH5rI38Vw46KCD8s+xvfnmm+Wvfe2119L++++fR9HFe3z9619PY8aMKX9+2rRp+Xznnntujb+PF154IZ/zySefXOrfUcXf0wcffJAOPvjgtPLKK+fzPP/88+lHP/pRWnPNNdMXX3xR43vGNe6+++7lj+O4Cy64IG288cb5/dZYY410zDHHpJkzZy7T73TKlCmpdevW6corr6zx/e+88858rU8//XSNzwNAeOaZZ9Iuu+ySunbtmlZcccVcFu6dd96pFL8uvfTSHNeiPRCxcN99902vvvpqpfNESbm99947x7Wf/vSnadVVV02dO3dO2267bbrvvvvyMR9//HE67bTTUu/evXN823zzzdO9995b7Zpmz56dTjzxxLTeeuvl9eDWWWeddNJJJ6VPPvmk/Jhf/epX+Zo+++yz/FzE5EIb4brrrlvmknvxXnHugjvuuCNtt912qUePHqlLly5piy22yG2n+CwAUKqaW58BADRlcf84cuTIfL+53HLL5bgbMe3xxx8vj3FxH/6zn/0srb/++uV9x0OGDElPPPFEeWyOY+N+95FHHimPhxXvX5fmHj9EHL/iiivyPXnhPv+AAw5Ib731Vvkxca0R28OOO+5YKf7Ge2655ZbpP//5T17TPWJ8PDdr1qxK1/GDH/wg30tHG2LrrbdO99xzT7XrGD16dOrXr1++344S9dGHcNlll+U2SFW33nprvieP86211lrpzDPPTAsWLKiT/4+gqWrb2BcALTl4f+9738sB7Ygjjsg3sv/+97/ThRdemB599NHyAB0j0yIYPvzww+nnP/95+spXvpITtBHUI1BGoB01alROCJ9wwgnpwQcfTMOHD8+d3nETHm688cachI5O90iGR4f37bffnh9HgB08eHCla/vDH/6Qg+rRRx+dttpqq9SzZ8/yjvk999wz799pp53ysfFceOyxx9Kuu+6aGyHRKIlGwvjx49OPf/zjNH369HTyySfnDvbvfOc7+XriWqsaO3Zs7hT45je/udS/owjaFX9PU6dOTaeeemoO+pH0j2uN94vOgIEDB1Z6v8mTJ6d//vOfufO/cI74XfzpT3/KDam45g8//DA3jiKBUdHS/k6j82HnnXfOyfbDDjus2me+6aab8meOhg8A1GTChAnp97//fR5ANnTo0BwLf/e73+WYHwPVIhZGnI7YHfErEuAzZszIsSviy1/+8pe0/fbbl58v4vk3vvGN1LZt2/TLX/4yvz6OjRv9cePG5c75GEAX7Y6I59Eu2GOPPdJTTz2Vk+Thvffey53q7777bo61Ee/iWmLA2sSJE3MbIAabFUTnQ5wzYm6nTp1ycjwS6vFZYl25LyOSEPE54ndw6KGH5n1///vf83kjjsfvCgBKTXPrMwCAph53I3a99NJL6aijjsr3vpHUjmR3YfBZxLlIOEfsjWNi4Hn0RUccjeTz3Llz8zmib/miiy7K982/+c1v8mv79u271Pf4MSA+EtyFfuroX48YH/f5cd5IiMf9eQyej8FvkViPfudf//rXaZNNNqkUf2MwfPRNx8CAaA/EfXr8HAqxPpL5cZ3RZog+gehDj/7wSOyHww8/PF1zzTW5rRAD7CJx/sADD+S2Roh2SkEk1gvtjmhvxL35Kaeckp599tn8ftBslQGN4sgjjyxbfvnly5588slK+ydNmpT3//rXvy4bM2ZM1IAp69SpU95f0b777lvWtm3bsvbt25f97W9/q/TcQQcdVLbWWmuVP37sscfKJk+eXO0aBgwYULb++utX2hfvF9sf//jHGq87novrqmju3LllvXr1Kttmm23KPvnkk0rPnXzyyfk6X3/99fz4xhtvzOeoej1ffPFF2RprrFF27rnnFvU7CoXf06qrrlr27rvvVrvmLbfcMn/Wqk499dSybt26lS1YsCA/vuiii/J5rr/++krHLVq0qOyEE07Izz300ENF/07//Oc/59dW/Rzz5s0rW2GFFcrOOeecaucBgDfeeCPHjzZt2pTdeuutlZ6L2N+qVauySy+9NMeROO6mm26qFp+/+c1vlvXs2bNs9uzZed/QoUPzsV/72tfK94X58+fn+BXtinXWWafsnXfeKX8u4mTfvn3LDjzwwPJ9u+22W9lKK61U9u9//7vSe95///2VYulpp51W1rp167J+/fpVayMcffTR+TP84x//yI+//e1v5+srXGc8rs3aa6+dzx1WXHHFsn322afaMVOnTi0bN27cYn7DANB0Nac+AwBo6o477riyDh06lD377LOV9se98i677JLj28UXX5z/femll6r1HV955ZVlH3/8cfm+mu5pl/YeP0QfeTy+8847Kx339ttvl6288splP/7xj6udt9BvXRD3zLF/k002yZ+jojfffLOsY8eOZXvvvXful69o//33L+vatWvuU5g1a1a+p4++8apefPHFsvvuuy//XGiTRD/Bq6++Wum4aLPU9HuD5kQZeWgEUarl6quvzjO6YiZYPC5sUXomZn/fcMMN5cfHLLDCqLSKM8SiTMtPfvKTXDa1ohhJHqPqoqx62GabbSqNniuI0XMxy2zOnDmV9sexhZFrSyNK0sXMtphZFiPbKn6eGPEW99tRPqZwbVGypuLnCzEKP85ReN9if0chRtPFbPaqYlR9lL+tWr4uRiXGCMEY0R9iBOG3vvWtPJK/ohjJ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Y8eWfeMb3yhbfvnly7p3757j5auvvlrpNXF8vK4mp512Wtnaa6+91M99/PHHZb/+9a/L+vbtm2N0xP9hw4aVTZo0qdrrHn/88bLdd9+9rHPnznnbddddy5566qnFfp45c+aUHXnkkWW9evXK54/2x/nnn5/bBnFsnDtMnTq1bMSIEWVf/epX87lXXHHF/HzEZQAoZc2tzwAAmrK3334735PGPWX0C3/nO9/J97ejRo0qW2+99coWLVpUduutt5btscceZauvvnq+947+72OPPbbsvffeq3SuiK2DBg0q69SpU1mPHj3KRo8eXfQ9fuE+f+utt86xOO7zBwwYUPaXv/yl0jG1nXdx9/gFL7/8ctm+++6b2xjxeTbddNOyc845p2zevHnlx7z00ktlRx11VNmGG26YryPu0eM6IuYvbf/8ktoPUOpaxf80dsIfoKHESL0o5x4z4BrDPffck2fOxyjB3r17N8o1AEBD+dWvfpVH87/55puNfSkAAABQoygP//Wvfz2XVq8oKrPFbPeosBZVXwBqoow80OzF2jaffvppeuCBB9Lzzz9fYwn5+hSl+G644YZc2idK1Uf5PYl2AAAAAIDGF0uR7bnnnnlJs0033TR16NAhvf7663nweKyNHkuUAdRGsh1o9p555pm8Ps6qq66aZ7RHg6khxVq1Z511VpozZ05eqzbWsgEAAAAAoPGdffbZaZtttsmz12Oi1scff5zXNf/e976XTjnllNyvDFAbZeQBAAAAAAAAoEiti30BAAAAAAAAALR0ku0AAAAAAAAAUCTJdgAAAAAAAAAoUttiX9ASLFq0KL399tupc+fOqVWrVo19OQDwpZSVlaW5c+em1VZbLbVu3fzH2YnjADQn4jgtyYwZM9K4cePSkUce2diXAlAnxHFako8//jhddtll6dhjj01t20o9AS0njrcqiyOp5K233kprrrlmY18GANSpadOmpTXWWCM1d+I4AM2ROA4ApUscB4DmG8cNL6pBjLwr/PK6dOnS2JcDAF/KnDlz8s1uIb41d+I4AM2JOE5dOvroo9Mdd9yR2rRpU2n/kCFD0u9+97vyx6NHj04XXnhh+uCDD9JXv/rVNGrUqLTxxhsv8fyffvppOv/889PYsWPT7Nmz01prrZV++tOfpv333z8//+6776bhw4env//97/m/7biODTfcMO/v2bNnTtK88MILqVu3bvXw6QEanjhOKcXxggULFqQdd9wxbbvttvm1BTG78xe/+EX661//mj766KM8y7NPnz7pww8/zHH85ZdfThMnTky9e/euo08MUBpxXLK9BoUSN9Eg0CgAoLloKSXcxPGW7ZVXXklPPPFEOuiggxr7UgDqlDhOXf1+TzvttHT88cfXesxVV12Vbr755vTwww/nZPmtt96a9tlnn/TMM8+kVVZZpdbXReHEH/zgBzkBEMn0eO2kSZPSgw8+WP7/ZZxniy22yImC1157Le20007p0EMPzcmDo446Kq288sr5dQDNjThOU4/jFZ188sk5wbTccstV+v/xhBNOyHE+BsdFIn+XXXZJ3/ve99Lvf//7nJR/6aWX0mabbVYnnxWglOJ4818oBmixxo8fnx566KHGvgwAGkB08McI+ujkt0oSACybmMl24oknpuuuuy6ts846ecZazJYbNGhQpZltNbn22mvT+++/n2677bbyhPmmm26a120tePzxx9NPfvKT1K5duzyj/bvf/W7utJ8+fXq6/fbbKx0LADRcHK/Ynxoz1A8++OBqz0Ucj4HtHTp0yOWU99prrxzHY632Cy64IJ1yyin18KkAmj7JdqDZ+eyzz9Itt9yS9t133xaxHhZAQ5sxY0a+8V599dVzmdcoLffAAw+Ul5X77W9/m77+9a/nEktxzM9//vN88704UXYuzlV1i1H00Rlf8Oqrr6bvfOc7qVOnTrnjIDrrY4Zcr1690tChQ9Pnn3+eDjzwwHr/HQBAc1SYBde3b99K+wcPHpzuuuuuxb728ssvL5/xVputttoqXXrppbncfJSLjxnwAwYMSOecc0468sgjU9euXevsswBAS/Nl4niIQXPHHXdcHkBX0yzOiOMxc37+/PnpzTffzJVqYsB7tAFilvt6661Xp58HoFRItgNLFGvuzJw5s9r+K664IjeiIpmy/fbb5xKBVcUaTQMHDsydJquttlo6/fTT06JFi5ZqJGbMaoj37t69e17jL9YCquj//u//0iabbJLat2+fO3TiPSK5s/baa6cRI0bk9/3KV77yJT89AFXttttuqUePHrlke9yMH3744WnPPffMJeNuvPHGHA9uuOGGnHiP2eb/+te/0s9+9rPFnjPON2vWrGpb3OhHidmC73//+7kEXpS0iw76KGv3q1/9Kg8AiJgUI+nb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6fiYyR4Ng7Fjx6Ybb7wxHXPMMfm5Aw44IK8jF+u/xvPnnXdeeuWVV9IhhxzS2JcPAFTxzjvv5Di96aab5tJ3kVivmnA3aA4Amgad9ABQ+tq0aZM22WSTdOmll6abb74571MxFgAaOdn+97//PXeCx1qs3/ve99L48eNTfTUE7r777hzgowRtjJr/wx/+kB544IE84y1ceOGF+floMKy00krpkUceSffff3/5aHsAoHHifazPHoPg3n///bRo0aJcejbWaz/88MPz7PYoE3/KKaekoUOHpunTp6cvvvgiD6gbN25cGjFiRL19LgBoCeryvl0nPQA0rProf4/77qgoE1SMBYBGTLZHEN5xxx1Thw4d8ozyKCcXAfiee+5J9WGFFVbIa8PNmDEjzZ8/P02YMCFtttlm5c9Hidmzzjorl6ONxsFdd92VVl999Xq5FgBoKeoi3kcS/aWXXkqbb755nuG2//77p4MPPjide+655cdEUn2vvfZK2267bb7pv/rqq3MnQs+ePevpkwFA81df9+066QGgNOL4Hnvske688868POvnn3+eHnrooXTooYemU089NT+vYiwAfDltv8yLf/3rX+ctyr4VbLfddnn9tgjiAEDpq4t4H6XiR48evcTjhg8fnjcAoOnE8Tjuxz/+cdpll11S27Zt8wy72jrpr7nmmlxW/pJLLsmd9FGpBgBovDgeS7BedNFFOXEeleai6sxll12WB8sVRMXY0047LVevmTdvXk7wqxgLAHU0s/0HP/hBvkGuyb///e9KQTnEzXesqQ4AlA7xHgBKV33H8eikj2Xc1lhjjVxx5qSTTsqd9JGAL7CsGwA0zTjev3//vDzrzJkz88z1xx9/vNo5VYwFgHpMtsfaa1/72tfyqPUIthXFTfQNN9xQad/YsWPzfgCgdIj3AFC66juO66QHgPrjfhwAStsSy8j/7ne/y+uwXXzxxXmNmP322y+XrenSpUs655xz0vbbb59vtL/+9a+nl19+OT3xxBPpwQcfbJirBwDqhHgPAKVLHAeA0iWOA0Azn9kejj322Dwy/amnnkpffPFF2mijjdJ5552XR9BNmjQpbbHFFrl0Tex/7rnn0jbbbFP/Vw4A1CnxHgBKlzgOAKVLHAeAZjyzPXTs2DGVlZXltdZipN2RRx6Z12jbYIMN0umnn57XZgMASpt4DwClSxwHgNIljgNAM5/Z/q9//SuXrTn//PPTiBEj0rvvvpvXhhk3bly69tpr85oyf/3rX+v/agGAeiPeA0DpEscBoHSJ4wDQzJPtd999d3r//ffTn//85/Tkk0/mdWIi0Ef5mgkTJqTf/OY36fjjj0877rhjmjhxYv1fNQBQ58R7AChd4jgAlC5xHACaebL9rrvuSqeddlp6+umn0yOPPJIuv/zyNHz48PLn99hjj7x2zODBg9PAgQPT3nvvnd544436vG4AoI6J9wBQusRxAChd4jgANPNk+/PPP58OOeSQ8sfDhg3LpWw+/PDD/52odev005/+NE2ZMiVttNFG6Y477qifKwYA6oV4DwClSxwHgNIljgNA6Wq7NAetssoqOYivvvrq+XGMmmvVqlXq1q1btWM7deqUzjjjjLq/UgCgXon3AFC6xHEAKF3iOAA082T7T37ykzR06NB00kknpfbt26dzzjknP47RdABA8yDeA0DpEscBoHSJ4wDQzJPtsT7MJ598ks4888y0YMGCvCbMqFGj6v/qAIAGI94DQOkSxwGgdInjANDMk+0xgu7UU0/NGwDQPIn3AFC6xHEAKF3iOACULnVoAAAAAAAAAKCuk+2vvfZaWrRoUVoWb7zxxjK9DgBoWOI9AJQucRwASpc4DgDNPNk+YcKEtMUWW6QnnnhiqU+6cOHC9Otf/zr179//y14fANAAxHsAKF3iOACULnEcAJp5sv0nP/lJDtz77LNP2m233dL111+fPvrooxqPff3119OZZ56Z1l133fTyyy+niRMn1sc1AwB1TLwHgNIljgNA6RLHAaC0tV2ag3bffff0yiuvpLPOOisde+yx6aCDDkorr7xy6tWrV+rcuXOaO3dumjp1apo1a1bafvvt0w033JB23HHH+r96AKDOiPcAULrEcQAoXeI4ADTzZHvo1KlTDvannXZa+vvf/55Hzb377rtpwYIFacUVV0x9+/ZN3/72t9Paa69dv1cMANQb8R4ASpc4DgClSxwHgGaebC9o3759XgvGejAA0HyJ9wBQusRxAChd4jgANLM12wEAAAAAAACAyiTbAQAAAAAAAKBIku0AAAAAAAAAUCTJdgAAAAAAAAAokmQ7AAAAAAAAABRJsh0AAAAAAAAAiiTZDgAAAAAAAAANlWz//PPP07333rusLwcASoB4DwClSxwHgNIljgNAM0+2f/zxx2nvvfeu26sBAJoU8R4ASpc4DgClSxwHgGaUbP/kk0/Sbbfdlv785z+nL774Iu9bbrnlUtu2bWt9zeTJk+vuKgGAeifeA0DpEscBoHSJ4wBQumqP1v/fnDlz0je+8Y20cOHCHPT79OmTHnrooRzs27Vrl4/59NNP0y677JLKysrS6quvnsaOHZsGDBiQ3njjjdSqVauG+BwAwJcg3gNA6RLHAaB0ieMA0Mxntl966aU5kEfg/s9//pPatGmTbrjhhtS6desc8EME9Ndffz396Ec/Sk899VTe16FDB4EeAEqEeA8ApUscB4DSJY4DQDNPtt9///3p2GOPzT+3b98+jRgxIt1999358dy5c9P222+fvvOd76SVVlopHXLIIbkxUAj2AEBpEO8BoHSJ4wBQusRxAGjmyfZ///vfaZ111il/vMUWW6SXX345/7zCCiukww47rFKQjwZBWNx6MgBA0yLeA0DpEscBoHSJ4wDQzJPtsVZMRSuuuGL64IMP8s9RxiZK1xx44IHlwT7K24TCYwCg6RPvAaB0ieMAULrEcQBo5sn2quu+fPbZZ+nzzz+vdlxZWVndXhkA0GDEewAoXeI4AJQucRwAmnmyPUbPVQzk7733Xh5dV2gITJs2LU2dOjUtWrQo7yv8K/gDQOlojHh/6KGHpk022aTa/iuuuCKtt956qXPnznltukmTJi3zewBAS+C+HQBKlzgOAM082d6nT5/03HPPlT9+9NFH0/rrr59/njlzZv65d+/e5cG98G8h6AMATV9Dx/s77rgjjR8/vtr+q666Ko0ZMyZNmDAhzZ49Ox1xxBFpwIABacaMGcv4yQCg+XPfDgClSxwHgGaebI8O7vPOO698/ZgLLrggDRw4MD/u0aNH3rdgwYLy4D5v3rzcQT5r1qz6vnYAoI40ZLx/++2308knn5x+//vfV9of5z/xxBPTddddl9ZZZ528Dt2QIUPSoEGD0qhRo+rkcwJAc+S+HQBKlzgOAM082X7YYYflkXUbbrhh+spXvpLXiznooIPyc5988kn+N/Z17Ngx/7zCCiuko48+Ope/AQBKQ0PF+xiBP3To0HTuueemnj17Vnru4YcfTmuttVbq27dvpf2DBw9Od91115f8hADQfLlvB4DSJY4DQGlru6QDIog/+eST6fbbb09t27ZNe+21V/k6MjGiLrRv3z498sgj+WfrqgJA6WmoeB+z2aNE3m677ZaT6xVNnjw5P1dVlMt77bXX0meffZbatWtX7fkY5R9bwZw5c5bp2gCgVLlvB4DSJY4DQDNPtodOnTrlWWgVRYd3xY5tAKC01Xe8f/7559PYsWPTE088UePzUQqve/fu1fZH2bzoZJg/f37q1q1btefPPvvsdPrpp9fJNQJAqXLfDgClSxwHgGZcRr42McrummuuqdurAQCalLqK91H6btiwYWnMmDGpQ4cOtXYu1LTmXOxr1apVecm8qkaOHJlmz55dvk2bNu1LXy8ANAfu2wGgdInjANCMZrbXpHXr1unAAw+s26sBAJqUuor3Tz/9dJoyZUracccdy/fFmnORhI/Z6v37989r0sXM96ridVFKvqYS8oVyerEBAJW5bweA0iWOA0AzT7YDACyt7bbbLn388ceV9sWa7UcddVR68cUX8+MoEx+J9Vifff311y8/LtatGzhwYINfMwAAAAAAfKlk++uvv55L1sRIujZt2uR/C1uUdA2xjuqiRYvSF198kWepFdaTWWuttdIKK6ywpLcAABpZU4j3USb+lFNOyevU3XrrralXr17plltuSePGjcsz4wGAphvHAYBlI44DQDNPtm+wwQY5kBcjgn80BP7v//4vfe973/sy1wcANICmEu9HjBiROxe23XbbNHPmzNSvX780fvz41LNnzzo5PwA0R00ljgMAxRPHAaCZJ9tfeumlPLIuOr4jgMd6qYXHFUfXhWgUFEbYxb/du3ev7+sHAOpAY8T7HXbYobyEfEXDhw/PGwCwdNy3A0DpEscBoJkn2/v06dMwVwIANBrxHgBKlzgOAKVLHAeA0ta6sS8AAAAAAAAAAEqNZDsAAAAAAAAA1HUZ+fDmm2+mnXbaKS233HJ5jZjYysrK8hZrw3z66afps88+S6+++mrq1KlTsdcAADQB4j0AlC5xHABKlzgOAM082d61a9c0cuTI1LZt29S6det00EEHpWuuuSZ16NAhP16wYEE6+OCDc+AHAEqTeA8ApUscB4DSJY4DQOlqVRbD44oUAX7evHlphRVWyI/jFG3atEmzZs1KXbp0SaVuzpw5uYEze/bskvk84556v7EvAaBF2fsbK6fmHtdKNd7XZxwXbylVpfSdBVQmjtcdcZxSVWpxfNb4ixv7EmCZdNvl6Do/pzhed8RxSpU4Ds0/ji/Tmu0R2CsqlLYBAJoP8R4ASpc4DgClSxwHgNKxTMl2AAAAAAAAAGjJlinZXnUUnbViAKD5Ee8BoHSJ4wBQusRxACgdbZf2wF//+te5fE2sD/P555+n3/72t6lt27b5508//bR+rxIAaBDiPQCULnEcAEqXOA4AzTjZHgF+4sSJabnllssBfr/99kuvv/56+uKLL/Kouvh34MCBqV27dvV/xQBAvRDvAaB0ieMAULrEcQBo5sn2KFtz99131//VAACNRrwHgNIljgNA6RLHAaCFrdkOAAAAAAAAAC2ZZDsAAAAAAAAAFEmyHQAAAAAAAACKJNkOAAAAAAAAAEWSbAcAAAAAAACAIkm2AwAAAAAAAECRJNsBAAAAAAAAoCUl2w899NC0ySabVNt/xRVXpPXWWy917tw5bb/99mnSpEmNcn0AAAAAAAAANE8lm2y/44470vjx46vtv+qqq9KYMWPShAkT0uzZs9MRRxyRBgwYkGbMmNEo1wkAAAAAAABA81OSyfa33347nXzyyen3v/99pf0LFixIJ554YrruuuvSOuusk1q3bp2GDBmSBg0alEaNGtVo1wsAAAClrKysLI0bNy7tsssuqVevXmnllVdOAwcOTK+++mql41SaA4CmRxwHgPrTuhQbBkOHDk3nnntu6tmzZ6XnHn744bTWWmulvn37Vto/ePDgdNdddzXwlQIAAEDzEJXjLrroojRixIj05ptvpqlTp6att9469e/fP82dOzcfo9IcADRN4jgA1J+SS7bHbPY+ffqk3XbbrdpzkydPzs9V1bt37/Taa6+lzz77rMZzLly4MM2ZM6fSBgAAAPxX165d0yOPPJJ22mmntPzyy6cOHTrkynKxf+LEiSrNAUATJo4DQP0pqWT7888/n8aOHVtrgJ83b17q3r17tf09evTIM+Lnz59f4+vOPvvs3LAobGuuuWadXzsAAACUqlatWuWtohjQ/uGHH6YuXbqoNAcALTCOm8QGACWUbP/kk0/SsGHDcimbGHlXk06dOqVZs2ZV2x/7ojHRsWPHGl83cuTIXBqnsE2bNq3Orx8AAACaixjQfswxx6QNN9wwbbnllirNAUALjOMmsQFACSXbn3766TRlypS04447pm7duuVt9913zw2B+HnvvffODYII/lXF66Jh0K5duxrP3b59+zyCr+IGAAAAVPfRRx+lgQMH5vvx22+/Pe9TaQ4AWl4cN4kNAEoo2b7ddtuljz/+OM9SL2x//vOf8+i7+HncuHFphx12yIn1qgn3aDREAwIAAABYdk899VTq169f2mKLLdKDDz6YB78HleYAoOXFcZPYACCltqkZiaB/yimnpKFDh6Zbb7019erVK91yyy05ER8z4wEAAIBlc88996Qjjzwy3XTTTWnbbbet9FxUmhs7duwyVZqLDQAovTgOADSzZHsYMWJEatOmTW4wzJw5M4/UGz9+fOrZs2djXxoAAACUpA8++CAdfvjh6b777ksbbbRRtecrVppbf/31y/erNAcAjU8cB4D6U9LJ9mgEvPjii9X2Dx8+PG8AAADAl3fbbbelQYMG1dhBH1SaA4CmSxwHgPpTMmu2AwAAAI0jZrpdeeWVeU3XqtsvfvGL8kpze+21V64017Vr13T11VerNAcATYA4DgD1p6RntgMAAAD1b9SoUXlbEpXmAKDpEccBoP6Y2Q4AAAAAAAAARZJsBwAAAAAAAIAiSbYDAAAAAAAAQJEk2wGAevfYY4+lwYMHp1VWWSV16dIlbb311unhhx+udMyiRYvSGWeckVZfffXUtWvXtPvuu6epU6c22jUDAAAAAMDiSLYDAPXumGOOSQMGDEivv/56+uCDD9IJJ5yQBg0alKZMmVJ+zMknn5wmTpyYnnvuuTRz5szUv3//tPPOO6cFCxY06rUDAAAAAEBN2ta4FwCgDsUs9k6dOpU/3muvvdJ9992X7r333tSnT580ffr0dMkll+SZ7N26dcvHHHvssemhhx5Ko0ePTkceeWQjXj0AAAAAAFRnZjsAUO8qJtoLPvnkk9SxY8f88z333JN22mmn8kR7QZSev+uuuxrsOgEAAAAAYGmZ2Q4ANKgoEX/99denZ555Jl122WV53+TJk/MM96p69+6dn1uchQsX5q1gzpw59XDVAAAAAABQmWQ7ANAgNthgg/TOO++k+fPnp+WXXz799re/zf+GefPmpV69elV7TY8ePdLcuXMXe96zzz47nX766fV23QAAAAAAUBNl5AGABvHqq6/mWeeffvppevLJJ9Ptt99evhZ7lJmfNWtWtdfEvs6dOy/2vCNHjkyzZ88u36ZNm1ZvnwEAAAAAAAok2wGABtWmTZu0ySabpEsvvTTdfPPNeV+UkH/ttdeqHTtlypTUt2/fxZ6vffv2qUuXLpU2AAAAAACob5LtAECjmD59euratWv+edddd0333XdftfXWY/b7wIEDG+kKAQAAAACgdpLtAEC922OPPdKdd96ZFixYkD7//PP00EMPpUMPPTSdeuqp+fl11103HXDAAWnYsGHpww8/zKXmzzvvvPTKK6+kQw45pLEvHwAAAAAAqpFsBwDq3THHHJP+8Ic/pDXWWCP17NkznXTSSemyyy5LP/7xj8uPufDCC3PJ+Cgxv9JKK6VHHnkk3X///Wn55Zdv1GsHAAAAAICatK1xLwBAHerfv3/eFqddu3bprLPOyhsAAAAAADR1ZrYDAAAAAAAAQJEk2wEAAAAAAACgSJLtAAAAAAAAAFAkyXYAAAAAAAAAKJJkOwAAAAAAAAAUSbIdAAAAAAAAAIok2Q4AAAAAAAAARZJsBwAAAAAAAIAiSbYDAAAAAAAAQJEk2wEAAAAAAACgSJLtAAAAAAAAAFAkyXYAAAAAAAAAKJJkOwAAAAAAAAAUSbIdAAAAAAAAAIok2Q4AAAAAAAAARZJsBwAAAAAAAIAiSbYDAAAAAAAAQJEk2wEAAAAAAACgSJLtAAAAAAAAAFAkyXYAAAAAAAAAKJJkOwAAAAAAAAAUSbIdAAAAAAAAAIok2Q4AAAAAAAAARZJsBwAAAAAAAIAiSbYDAAAAAAAAQJEk2wEAAAAAAACgSJLtAAAAAAAAAFAkyXYAAAAAAAAAKJJkOwAAAAAAAAAUSbIdAAAAAAAAAIok2Q4AAAAAAAAARZJsBwAAAAAAAIAiSbYDAAAAAAAAQJEk2wEAAAAAAACgSJLtAAAAAAAAAFAkyXYAAAAAAAAAKJJkOwDQIMrKytK4cePSLrvsknr16pVWXnnlNHDgwPTqq69WOu6KK65I6623XurcuXPafvvt06RJkxrtmgEAAAAAoDaS7QBAg5g9e3a66KKL0ogRI9Kbb76Zpk6dmrbeeuvUv3//NHfu3HzMVVddlcaMGZMmTJiQjz/iiCPSgAED0owZMxr78gEAAAAAoBLJdgCgQXTt2jU98sgjaaeddkrLL7986tChQzrxxBPz/okTJ6YFCxbkx9ddd11aZ511UuvWrdOQIUPSoEGD0qhRoxr78gEAAAAAoBLJdgCgQbRq1SpvFX322Wfpww8/TF26dEkPP/xwWmuttVLfvn0rHTN48OB01113NfDVAgAAAADA4km2AwCNtob7MccckzbccMO05ZZbpsmTJ6c+ffpUO653797ptddey4n5mixcuDDNmTOn0gYAAAAAAPVNsh0AaHAfffRRGjhwYE6w33777XnfvHnzUvfu3asd26NHj5yYnz9/fo3nOvvss3Mp+sK25ppr1vv1A7R0r7zyShozZkxjXwYAAABAo5JsBwAa1FNPPZX69euXtthii/Tggw+mbt265f2dOnVKs2bNqnZ87Ivy8x07dqzxfCNHjkyzZ88u36ZNm1bvnwGgpYrBTxMnTkw/+MEP8s8AAAAALZlkOwDQYO6555609957p+uuuy6ddtppqXXr/zVFooR8lIuvasqUKbmUfLt27Wo8Z/v27fOa7xU3gOamZ8+eaebMmdX2z5gxIx188MH5+ZVWWinttNNO6fHHH6/1PLH0xhVXXJG23nrr/H25yiqrpGHDhlU796uvvpq+853v5IFQ8V0d38ExSKpXr15p6NCh6fPPP08HHnhgvXxWAAAAgFIh2Q4ANIgPPvggHX744Wn8+PFp2223rfb8DjvskBPrVRPuUWY+Ss4DtESxhMYFF1yQ3n///WrPxb5vfetbefmMf//73znxHtU+pk+fXuv5HnrooXTXXXflc0Y1kFjOo23btmnIkCGVjvv+97+f9tlnnzRnzpz097//PS233HLpV7/6VX6P9dZbL51yyin5dQAAAAAtmd4RAKBB3HbbbWnQoEFpo402qvH5KBMfyZuYMXnrrbfm2ZO33HJLGjduXHr66acb/HoBGtvll1+ehg8fnhYtWlTj88cff3zaa6+90umnn16+77vf/e5iz7nddtulXXbZpfxxjx498kz37t2758R6zHaPwVEx8OnQQw/Ns9pjgFTMam/Tpk3+Pv7Xv/6V9t9//zr8pAAAAAClycx2AKBBROLmyiuvzCWJq26/+MUv8jEjRozIiaNI7HTt2jVdffXVeSZ8lEcGaGmiGsjHH3+cFixYUO25WbNm5cofxx13XFHnjIFNVX322Wfly3KEFVdcMS/fcckll+Ry8Y888kh666238ndzJPZjYFQk3gEAAABaOsl2AKBBjBo1KieM5s2bV2377W9/W35czOJ888038/4od1zbTHiAlixmmK+11lrp008/TQcddFBaY4010tprr52OPvroPEN9aUQi/aWXXko//OEP089//vPyZHuIUvN//vOf06qrrpp++ctf5oojMWgqtv32268ePxkAAABA6ZBsBwAAKDHvvfdeTrTvuuuuaYcddkivvPJK+sc//pHeeOONNGzYsMW+9sEHH0zdunXLJeM32WSTNG3atLTHHntUOmbDDTdM999/f14X/rHHHktbbrllXrP91FNPTa+//nraeeedc+n5mO3+3HPP1fOnBQAAAGiarNkOAABQYpZbbrmccJ84cWLaYIMN8r5YlmPs2LFplVVWSe+++27q1atXja/9zne+k8vQh08++ST95S9/yeu4x2z2b33rWzW+5tlnn82J/L333jttttlmaciQIenOO+9Mf/zjH3Oi/tVXX62xRD0AAABAc2ZmOwAAQImJBHtZWVlad911K+2PGeurrbZaXo5jaXTo0CEn0H/84x+ncePG1XpczGo/7bTT0r/+9a+c5D/ppJPSCiuskH7605/mJH+UtQcAAABoaSTbAQAASkyUf1999dXTtddeW2n/jBkz0ttvv5169+6dHy9atGipzjd9+vTUtWvXWme1/+c//8lJ+Ujwt27dOrVq1ar8+TZt2uR9AAAAAC1NSfWIRMdOzLaIEodREnHllVdOAwcOzCULK7riiivSeuutlzp37py23377NGnSpEa7ZgAAgLoWye5LL700/eIXv0g33HBDWrhwYU6I77vvvumQQw7J90ph0003TWeffXb56/7+97+nAw88ML300kv58Zw5c/LzsY77YYcdVuN7nX766XlWe7xn375900orrZRGjRqVPv/885zsnzdvXtpiiy0a6JMDAPBl9ezZM82cObPafv3qANDMk+2zZ89OF110URoxYkQuizh16tS09dZbp/79+6e5c+fmY6666qo0ZsyYNGHChHz8EUcckQYMGJBneAAAADQXsfb6HXfckS6++OLUvXv3tO222+ZO0QsvvLD8mC5dulRaS33LLbdMX/3qV9MBBxyQn9too43S5MmT89rvUX6+queeey5NmzYt7bnnnuWz2GOt9vHjx+eke3TIxuMoKU/LopMeAErP/Pnz0wUXXJDef//9as/pVweAZdM2lZAoa/jII49UKll44oknprFjx+bOoW222SY/fvzxx9M666yTnx8yZEh64okn8syLc889txGvHgAAYNmrfNVkxx13TP/4xz9qfV3cC1Vdo/3444/P29KIztXLLrus0j3Y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nu+zzz5L8+bNq9NzAqVLHIf6JY4D9cF3CzQsbeaWTbIdqDevvPJK6tu3b+rXr1/afPPN0yabbFJrQ2/u3Lnpq1/9atpqq63ysS+88EKl55dbbrk6byQC0DDEA6hf/fv3T2uvvXbq06dP2njjjdPXvva1/HcWj9ddd93UuXPndM4551R6zYQJE9Iee+xR4/mefvrptPPOOzfQ1QNNnTgO9UscB+qD7xZoWNrMLVurssUNnwBYBtddd11q3bp1+daqVas8Uuvzzz9Pn376afrkk09Sp06d0rBhw/Lxl19+ed4XQaRt27blo7dixOTWW2+dvvGNb+TjIwjFuQAoDeIBNA3f/e5303HHHZcGDBhQvu/xxx9Pu+yyS1pvvfVSu3bt8t9d/G3G31v8ja255pq5sw1oucRxaBrEcaA++G6BuqHNTPjv/5MAdeidd95J7du3z1sEjAgyMRIrAszChQtz4Fh++eXLj4+RlIXg0qZNm3xsBKIISrG/IB4LMAClQzyAxhd/L88++2y+Ya8o/h632267dM899+SfK3rqqafSyJEjG/hKgaZGHIfGJ44D9cF3C9QdbWaCZDtQ50488cT05ptv5tGRM2bMKA8KETiiNMqZZ56ZVlhhhfLj999//3T33Xen3/zmNznwzJ8/P2244YbpsssuS126dCkf3RWlj2JU5euvv95onw2ApSceQOObPHlyWmWVVdKKK65YaX/c8MffZNVOtBD7omMAaNnEcWh84jhQH3y3QN3RZiYoIw/Ui8MOOyyvATR8+PBK+3/2s5+lr3zlK+noo48u3xcNtZVXXjk988wzuUxROOaYY/K+k08+OT+OkWFROqXi6C4Amj7xABrXpZdemiZNmpSuuOKKSvujRGTc5BdG4McWnWsxoj62WD9u3LhxjXbdQNMgjkPjEseB+uC7BeqWNjNmtgP14oADDsjB5d13383r+YRp06alxx57LB100EGVjo3RXjFKK0aArbPOOjmQxCiwwutCofSKAANQWsQDqD8TJ05MP/zhD/PfQ4yIjzJ08XcUo+ALo+mnT5+ef7733nvz30+Uf+zVq1faZpttjJAHlkgch/ojjgP1wXcLNDxtZsxsB+pNfL289tpr6YQTTsgjH/fZZ5+08cYb11iK6J///Ge64IILcoMuyqrstNNO6ec//3luEIYYAfb888+njh07NsInAeDL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue # ๋ฐ์ดํ„ฐ ์—†์œผ๋ฉด ์Šคํ‚ต\n", + "\n", + " # ๊ตฌ๋ถ„ ๋‹จ์œ„(img + txt) ๋น„์œจ ๊ณ„์‚ฐ\n", + " ratio_df = mall_df[\"๊ตฌ๋ถ„ ๋‹จ์œ„(img + txt)\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " # ์ œ๋ชฉ ๋ฐ ๋ผ๋ฒจ ์„ค์ •\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"๊ตฌ๋ถ„ ๋‹จ์œ„(img + txt)\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์„ฑ๋ถ„ ์ •๋ณด & ์„ฑ๋ถ„ ํ‘œ๊ธฐ ๊ฐ€๋…์„ฑ\n", + "- ์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฐœ์ˆ˜ ํŒŒ์•…\n", + "- ์„ฑ๋ถ„ ํ‘œ๊ธฐ ๊ฐ€๋…์„ฑ ์ข…๋ฅ˜์— ๋”ฐ๋ฅธ ๋น„์œจ ํŒŒ์•…" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB9sAAAH/CAYAAAD38r1XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAcV9JREFUeJzt3QeYnFX5P+6TAiGQCoTeCaFLBwVBIigtEClKJ4AgXaqRjghSBKWJdAHpGDrSe5UmSgdpEkMNkF4Iyfyv53z/s7+tyb7JbnZn9r6va8ju1HeG3f2c9zyndCqVSqUEAAAAAAAAADRb5+bfFQAAAAAAAAAIiu0AAAAAAAAAUJBiOwAAAAAAAAAUpNgOAAAAAAAAAAUptgMAAAAAAABAQYrtAAAAAAAAAFCQYjsAAAAAAAAAFKTYDgAAAAAAAAAFKbYDAAAAAAAAQEGK7QCNeOihh1KnTp3SY4891taHAkAH8+GHH3aoDNp4443Tnnvu2daHAQAAAFVx7v/OO+/kc+2ePXumRRddNH366adpdrrqqqvye4OOomtbHwAAAAAAAAAw67bffvv0zTffpAsuuCB9++23qVu3bm19SFDVzGwHpitGoMVINAAAAIAZ0Y8AAHXFam4x03x2+Prrr9Nrr72Wfvvb3+bX3WeffVLfvn1ny2tDR6XYDgAAAAAAABVuzJgx+d8FF1ywrQ8FOgzFdgAAAAAAAKhwpVKprQ8BOhzFdpiNJk+enE4//fS00korpbnmmistssgi6aCDDspLu4RYZm3++efP+6icccYZafnll09zzz13vn/srzJt2rR8v7/+9a9pjTXWSN27d09LL710+uMf/9jgtW666aa06aabpj59+uTXivvfeOONjS7vdvfdd6dLL700DRgwIHXp0iUddthheVmbuC3stdde+eu4fPjhhzWPfffdd9Nuu+2WR8nFa6y++urpyiuvrLl9+PDh+fnOOuusRj+PV155JT/nc8891+zPqPbn9OWXX6a999479evXLz/Pv/71r7TrrrumxRdfPE2dOrXR14xjHDRoUM33cb9zzz03rbzyyvn1FltssXTooYemkSNHztRn+s4776TOnTunSy65pNHXv/322/Oxvvjii43eDgC1vfTSS2nzzTdPvXv3TvPNN19e/u2TTz6pk2MXXnhhzrdoF0Qm7rzzzuntt9+u8zyxdNwOO+yQ823//fdPCy+8cOrZs2faYIMN0gMPPJDvM2HChHTSSSelZZddNufcmmuume6///4GxzR69Oh09NFHp2WWWSbv+7bUUkul4447Lk2cOLHmPr/5zW/yMU2ZMiXfFtlcbitcffXVM720XrxWPHfZrbfemjbccMM077zzpl69eqW11lort6HivQBANai2fgQAqBRxXnnMMcfk89A555wzZ3Dk2zPPPFOTd3F+/stf/jL179+/pm95p512Ss8++2xNTsd94zz48ccfr8nG2ue1zTn3D5HpF198cT5XL5//77777ul///tfzX3iWCPnw8CBA+tkcbzm2muvnf773//mPd0j7+O2UaNG1TmOn/zkJ/kcO9oT3/ve99Jdd93V4DiuuOKKtM466+Tz8FiiPvoW/vznP+f2SH0333xzPleP51tiiSXS7373uzRp0qQW+X8E7UXXtj4A6EjhvNlmm+XAOvDAA/NJ63vvvZfOO++89NRTT9UEcIw8i7B77LHH0uGHH56WW265XKCN0I4gjCA9++yzc0H4V7/6VXr44YfTkUcemTu744Q7XH/99bkIHZ3tUQyPju5bbrklfx8BuuOOO9Y5tr/85S85NA855JD03e9+Ny2wwAI1HfLbbrttvv6HP/xhvm/cFp5++um05ZZb5kZGNDqiEXDfffeln//852nEiBHp+OOPzx3rm2yyST6eONb6rr322twBsN566zX7M4pQrv05ffTRR+nEE0/MoR5F/zjWeL048R88eHCd13vzzTfTv//979zpX36O+Cxuu+223FCKY/7qq69y4ycKF7U19zONjoYf//jHudi+3377NXjPN9xwQ37P0bABgOl55JFH0h/+8Ic8kGzIkCE5E3//+9/n7I8Ba5GJkdeR4ZFjUQD/7LPPcoZFzvz9739PG220Uc3zRa6vu+66qWvXrunYY4/Nj4/7xgn9sGHDcod8DKSL9kfkerQPtt566/T888/nInn4/PPPc0f6p59+mjM3ci+OJQauvfDCC7ktEIPOyqKTIZ4zsrdHjx65OB4F9XgvsX/crIjCQ7yP+Az23XfffN2TTz6ZnzfyPD4rAKhk1daPAACVlMGRY6+//no6+OCD8zlxFLWj2F0eiBaZFwXnyOG4TwxIj77qyNQoPo8dOzY/R/Q9n3/++fl8+tRTT82PXWGFFZp97h8D5aPAXe7Hjv73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wfUXX3xxWmaZZfL+FBtttFF69dVXG9wn9l0aPHhw6t27d1pkkUXSySefnKZNmzbD15w0aVI67LDD8mv37ds37bbbbunrr7+uc5977rknrbLKKqlbt26pS5cu+TVWX331tOSSS6ahQ4fm111uueVm8d0D0ByvvfZa2nzzzdN8882XFlpooXT44YenCRMm1NweX//qV79KSy21VOrRo0f60Y9+lP79738367n/9re/pTXXXDP/nY9BVJEP48ePr7n97bffTptsskl+3s6dO6c55pgjrbXWWvk4hgwZkr799tu0xx57tMr7BoD2mJ//+9//8uNWWmmlvDTv8ssvn84999w695GfANBx2xjhz3/+c01bIfp4o9926tSpM3zuyy+/PK288sq5DfGd73wnDRs2rM7t2hhAR6fYDtSIQkZ0yHzxxRcNbrv00kvzcj+PPPJIGj16dDrwwAPTFltskT777LM6j990003Tlltumb788sv00ksvpaeeeio33GZk7733zo9/991304gRI3Khftttt625/YMPPsiNsiuuuCI3FM8555w0ZsyY9MQTT+THRKPthBNOaMFPA4Cm/Oc//0kbbrhh+tnPfpY+/vjj9OKLL+a/0zHoqTzAKv6Gv//+++kf//hHzpXtt98+DRw4ML3++uvTfe677rorHXXUUXmA16hRo9LTTz+dB3f94he/qLnPNttsk37605/mHHjyySfTnHPOmX7zm9/kTIoOg8iDrl27tvrnAADtJT8jN2OQ2gMPPJDP12655ZbcMV674C4/AaDjtjEuuOCCdNlll+U2QrQV4tz7tttuSyeeeOJ0n/v000/P/bDXX399Pkf/wx/+kAfEX3311TX30cYAOrpOJet3NBChECepEToxygs6gosuuigdeeSRuQE2efLk3LEz//zz18w6j+L3M888k1ZYYYWaxxx66KG58XTWWWfl788888z08ssvpxtvvLHmPp9//nnq379/buDFyMrGPPfcc7lBFp1KtRteMWv9d7/7Xdpqq61yQzAahY899li+LYrrc801V27kRcfSm2++mQvx0BHJrcb5XFrPIYcckke/x6j4ssiOmI1+3HHH5dl0MaL+ww8/TPPMM0/NfU499dQ8SCoKAU2JgVVrrLFGHoVfFtkSA7k++eSTPJgrVkH55ptv8ionIVZbOfroo/P1u+66a3rjjTdqbgOoJLKruj+X1szPeN762Rezzs4///z8WPkJMPtUS261NJ9L27Uxdtlll5z7cZ5de3JTFNt///vfp2effbbR543njP7caIOsu+66NddHQT2Whv/vf/+bX0cbA+jo2WVmO5AdcMABecZ4FNbriwL3EkssUafQHnbcccd0xx131Gmg7bTTTnXuE42q7373u+n+++9v8rXjcdttt12DEY4xGrP8/NE4fOWVV/JM+Si0R+E9ZtHH0kTnnXdeOv7442f6vQNQfNR8/G2vLbb4+PnPf5479uP2VVddtU6hIOy///7p0UcfzQOlmtKvX7+8/F1tjz/+eFpvvfXy13Giv+yyy6Y//elPOQ/itlg6d4MNNsgrqcSIeSfxAHS0/Gws+2I2WblDSH4CQMdtYzTnXLsxMRlr3Lhxae21165zfcyiX3TRRfMKqNoYAIrtQDPErPEBAwY0uD4aUrGE+5QpU2Z4v7htZp6//Lill146/fWvf00HH3xwzSz7WK4oZuTHcvZxOwCzx+KLL57eeeedBtd/9NFH+fq4/b333muw91usYBKDpCI7mvLrX/86z8DbYYcd8mCs+Lv/8MMP56Vwy2Ig1t13350WXnjhdOyxx6abb745P2dcYsQ+AHS0/Kwvlp2PDu7YmqVMfgJAx2xjhFg9NPpR99lnn9wm2G233dJXX32VTjvttCafNwr0sf96tEVqi8fFdqDl59bGADo6xXZghmIEY9++fRtcP++886bYiSIaVzO639ixY2fq+Ws/btCgQelf//pXXpr+b3/7W+rZs2ee1R7LIcVyRquttloeTRkz7hvbdx6AlhGj4y+88MJ0zz335JHrsXRcXPf888/n72N5ufgbHkvUxTJLsXLKVVddlWfmxd/7uM/0TuZPOeWUvCzdNddckx588MH09ddf19mrdsUVV8zXx9/62NM9RtnHfnCx11x0Avz4xz/OrxMj6WMJegCo9vys7dZbb00/+tGP8rnSxhtvXHO9/ASAjtnGCLHN5zHHHJML49dee21ePTTaBNMbzBcz0vfee+/8XLHNTTxXrIAa7Yzoly0/tzYG0NEptgMz1KNHj0aXLIzrOnXqVLPM4fTuFw2wmXn+6T0u9mqP/dxjn/lYcj72GIrGZOzlvu+++xZ4hwAUEcvTXXfddXnG3EILLZS23377vCdbDH6K72Pke4xqjxPtOOleaaWV8mCpOPmO2Xpxn8bEbbFXbTw2lreLYsHbb7+d93qL7UbipL0x//znP9MHH3yQZ8PHvnFxLCNGjEi777572nrrrWsGhQFANeZnWeyVethhh+XO7XjMzjvvPN37y0+AjiW2ehw5cmSj/WvLLLNM7oOLLHj11Vcb3Gf48OFp8ODBed/aWHEysiz646iMNkZMZlpnnXVywTyK3zGJKf6N/tSBAwfmlXWa8oc//CEXyTfZZJO02GKL5eXiY7XR5ZZbrsm2iTYG0NEotgMzFEu8NzbKMZYKiqXeo1NoRverv997c5+/qcdNnDixZlb7vffem0dUbrbZZrlwf+aZZ9aM5ASgdWy55Zbpueeey501L774YhoyZEju2P/+97+fb4/922644Yb08ccf5xP6c889N3fQxL5xSy21VKPPGY+Pvd1iRnvMcK+9sslee+2Vn68xUVQ46aST8j51sfpJZMPcc8+dZwJGLsTxATDzdM637/wMkydPzrPGovM6ZrGtvPLKMzwW+QnQMUQ2RJ40tgrkpZdemq688sq893asqnLggQfm7Ro/++yzOo/fdNNNc4Z9+eWX6aWXXsqzoiPTqYw2RhTiY4n3KJyXJzbFFjVxnh3F9tjCrSkxqSmWmo+C/Keffpr3gF9++eXz3uxRhG+MNgbQ0Si2AzMUSw9G4bt+QfyWW27JHWe1iyGxJ09t0cCLhl7MVCyr37kWj4vnqr83YcxorP389Tv2YiRkjKiMpeyjgVh7iaPa3wPQ+mLUehTJY3m5xsTf6uOPPz4ddNBBNdc1VmyJFVPi0thec7UL8LVHzMeqJjFivpwHtR8vEwBmns75ysnPU089NS299NLpsssuy53iMyI/ATqG2KM7zqNitbD6Jk2alK+PWcoxoCv+7u+00055VvTZZ59dc7+YybzGGmuk/fbbL3Xt2jUXbaN4e8455+R8pzLaGI3lerQBYlBf+Vy7uQMi4/99/EzE7Pb6tDGADqlEA6NHjy7FRxP/QkcUP/9ffPFFnevOPPPM0vrrr1/63//+V/r2229L1113XWnxxRcvffbZZzX3+eqrr/J1f/nLX0pTp07N991kk01Kv/nNb2ru88wzz5TmmWee0vvvv1/n+bfYYovSAQccUBo3bly+HHnkkaWBAweWpk2b1uD4JkyYUFpqqaVKI0aMyN/Hc/Xp06f02GOPlSZNmlTad999S9tvv30rfDLQPrXn3OrXr1+DvyfhoosuKi299NKlHj16lDbccMPSK6+80uA+H330UWmbbbYp9erVq7TwwgvnvyXxt6UaPpdqcOyxx5Y++eST/PWjjz5a6t+/f+nCCy+suf3SSy8tPffcc/nv+Mcff1zaddddSxtssEHpm2++ybfH3/r4+bj++utrHjN+/PjSiiuuWNp///1zhoR4jV//+tcNMqcsfkZuueWW/HXk08orr1w666yzSlOmTCldeeWVpSWWWCI/L0AlaE/Z9ec//7nUvXv3Urdu3RqcH0ycOLHUt2/f0ptvvlnnMb/85S9LRx11VM33Z5xxRmnHHXesc5/4W96zZ8/SyJEjK/JzaY/5GRZZZJFG21xNkZ8Arae95lb9PL/33ntLq622WoP7Pf3006Xllluu5vv11luvdNtttzW4349+9KPcP9iU6KOLz6B8GT58eLv8XKrF9NoYcf2CCy6Y+1WiDRbtjA8++KC05557llZfffXc1xpWWmml0mmnnVbneR988MHcZpg8eXJuG0QfcbQ76vftlmljAB0x09vlECJL1EH7M3To0LxfbiwPFL9fMWPivvvuy7+vZX379k0PP/xwnt3ep0+fvBdQLEV04okn1tyne/fueY/38tLzZTfddFP+XY2RtLF0YvwNiJntjc1ujL8F22yzTf4dDzGD48Ybb8yzPWKvoK+++irfB2g7ZsJVv+iriUyIdtnhhx+ezjjjjPz/smyJJZZIRx11VM6MtdZaK/99vv/++2v+/s8555x5GbnIhbL4/tFHH81/+zfccMP83PFvLI0bPwO1Mye8/PLLue237bbb1oyQv/3223M+zT///DkL4vt4XgCKOeCAA9KECRPyrLf6Hnvssfx3vv6WTzvuuGO64447ar6PJUljhlxt8bc89hWNTOiIWiM/x40blz755JN8LhVLs9a/RHurNvkJQHjzzTfz1o71xZaRsbrllClTZni/uK0pp59+es6z8mXxxRdv4XdAc9sY0Z54+umn88qlMSM9/n9Ef0u0HZ588smadkWvXr1yv21tcZ/yMvTRZ/vCCy/k54r+2Pq0MYCOqlNU3FM7ER3rUcCLMIjO+fgDXLtj/oorrsgFuTj5jGJenIBGx+uCCy5Y8/g111wzHXHEEXl5lHiOPfbYI62//vqFOufHjBmTAydOSCNggPYlGmY/+clP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aYMNNkhXX311WnvttdP888+fvve976UHH3ww3/7mm2+mAQMGNHjcsssum29ryuTJk9OYMWPqXACgGs10sf2zzz5L//73v9Nzzz2X/vOf/6Rvv/02tSYd8wDQ8mZ3nged8wBQ+ZneWh3zQec8AB1VW5yjf/755+n888/P5+LRt/7xxx+noUOHpu233z699NJLady4calv374NHjfvvPOmsWPHNvm8p59+el59tnxZfPHFW/mdAEAFFNsj4A899NC09NJL50L3mmuumU+mV1hhhRyYMZP82muvTVOnTm3xA9UxDwAtoy3zPBg1DwCVn+mt1TEfdM4D0JG09Tn6nHPOmVZaaaU0bNiwtOKKK+bvt91223TAAQekyy67LPXo0SONGjWqwePiulh1tinHHHNMXp22fBk+fHirHD8AVESxfeLEienwww/PQR+hGPukP/roo+mVV17JM85j6fa//vWvucM89kxfeeWV08MPP9yiB2rUPADMmvaQ58GoeQCo/ExvrY75oHMegI6gPeR5iJVhl1pqqQbXR85/+OGHuc/93XffbXB7HGMMCGhKt27dUq9evepcAKAadZ3RHSLUd9lll7TJJpukt99+O4+ua0w0CqKT/IwzzsgzyQ8++OC08cYb5/3VW7JjfqGFFsod81FE//vf/55fMxoh0TEft83sqPlYjh4AqlV7yfPanfOXXnppzXXROf+Pf/xjlkfNR+dEWQyeU3AHoNq0l0yfXsf8DTfckLbeeuv0yCOPFO6YL3fOxwUAqlV7yfMQz3/CCSfk8+m55pqr5voXX3wxF9q33HLLdPTRR+dz7NoF81tuuSUNHjy4xY4DAKp2ZvsHH3yQZ5NffPHFTYZ+fRGy//rXv9Jiiy2WWopR8wAw89pLngej5gGg8jM9OuavuOKKNGnSpDrX1+6Yf+CBBxqsHKdjHgDaT56Xt2GNJeyjrz3Oyb/55pu8bP31119fs7z97rvvnvbcc8/01Vdf5dv/+Mc/prfeeivts88+LXosAFCVxfaf/exnaf311y/8xNHhfdxxx6X23jFfPlad8wBUs/aS50HnPABUfqbrmAeAys/z0KVLl3TnnXfmPvT11lsvb+v2l7/8JT300EN5ddlw3nnn5dtXWWWVvL3r448/nrd3rT0THgA6qmbt2d4e6JgHgOqgcx4AKp+OeQCoHnPPPXc655xz0meffZbGjx+ft4JZY401am6fY4450mmnnZY+/vjj3P8eS9ovuuiibXrMAFA1xfYnn3wyF7NXXnnltNlmm6X77rsvtQYd8wDQemZXnged8wBQHZmuYx4AKj/PAYA2LLbHTPKBAwem7t275yL3ggsumBsBd911V2ppOuYBoHXMzjwv0zkPANWR6QBAy5LnAFBZOpVKpdLMPnjDDTfMy7cfc8wxNddddtll6U9/+lP697//nSpVdOr37t07jR49uiL2bx/2/BdtfQgAVWmHdfuljpBb8rw42UslqZS/ZYBMb43PRWZXD3kGVAp53jjn6PB/tGmg+rJrhjPbf/KTn+Sl2Bvz3nvv5eCvbfPNN8/LvAMA7Yc8B4DqINMBoPLJcwCoHjMstg8YMCCtttpqad99981LudYWy7Vfd911da6LfdTjegCg/ZDnAFAdZDoAVD55DgDVo+uM7vD73/8+T5G/4IIL8n4xu+yyS17CJqbLn3HGGWmjjTZKzzzzTFp99dXTG2+8kZ599tn08MMPz56jBwCaRZ4DQHWQ6QBQ+eQ5AHSgme3hsMMOy+vSP//882nq1KlppZVWSn/84x/zaLpXX301rbXWWnkZm7j+5ZdfTuuvv37rHzkAUIg8B4DqINMBoPLJcwDoIDPbwzzzzJNKpVKaa6658qi7gw46KB133HFp+eWXTyeffHI677zzWv9IAYBZIs8BoDrIdACofPIcADrQzPb//Oc/eQmbc845Jw0dOjR9+umneZ+YYcOGpauuuirvL3Pvvfe2/tECADNNngNAdZDpAFD55DkAdKBi+5133pm++OKLdPfdd6fnnnsu7xkToR9L2TzyyCPp1FNPTUcddVQaOHBgeuGFF1r/qAGAwuQ5AFQHmQ4AlU+eA0AHKrbfcccd6aSTTkovvvhievzxx9NFF12UjjzyyJrbt95667yPzI477pgGDx6cdthhh/TBBx+05nEDAAXJcwCoDjIdACqfPAeADlRs/9e//pX22Wefmu/33HPPvKzNV1999f+eqHPntP/++6d33nknrbTSSunWW29tnSMGAGaKPAeA6iDTAaDyyXMAqA5dm3OnBRdcMAf6oosumr+PEXSdOnVKffr0aXDfHj16pN/+9rctf6QAwCyR5wBQHWQ6AFQ+eQ4AHajY/otf/CINGTIkHXfccalbt27pjDPOyN/HyDoAoDLIcwCoDjIdACqfPAeADlRsj71iJk6cmH73u9+lSZMm5f1hzj777NY/OgCgxchzAKgOMh0AKp88B4Dq0KlUKpXa+iDamzFjxqTevXun0aNHp169eqX2btjzX7T1IQBUpR3W7ZcqQaXlVjV8LrKXSlIpf8sAmd4an4vMrh7yDKgU8rxxztHh/2jTQPVllzVpAAAAAAAAAKCgGRbb33333TRt2rQ0Mz744IOZehwA0LLkOQBUB5kOAJVPngNAByq2P/LII2mttdZKzz77bLOfdPLkyemUU05Jm2666aweHwDQAuQ5AFQHmQ4AlU+eA0AHKrb/4he/yCH+05/+NG211VbpmmuuSV9//XWj933//ffT7373u7T00kunN954I73wwgutccwAQEHyHACqg0wHgMonzwGgenRtzp0GDRqU3nrrrXTaaaelww47LO21116pX79+aaGFFko9e/ZMY8eOTR999FEaNWpU2mijjdJ1112XBg4c2PpHDwA0mzwHgOog0wGg8slzAKgOnUqlUqnIA2K5mieffDKPoPv000/TpEmT0nzzzZdWWGGF9IMf/CAtueSSqdKNGTMm9e7dO40ePTr16tUrtXfDnv+irQ8BoCrtsG6/VK25Jc9njeylklTK3zJAprdGpsvs6iHPgEohzxvnHB3+jzYNVF92NWtme23dunXL+8LYGwYAKpc8B4DqINMBoPLJcwCo4j3bAQAAAAAAAIC6FNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAmF3F9m+//Tbdf//9M/twAKAdkOcAUB1kOgBUPnkOAB2o2D5hwoS0ww47tOzRAACzlTwHgOog0wGg8slzAKjSYvvEiRPT3/72t3T33XenqVOn5uvmnHPO1LVr1yYf8+abb7bcUQIAs0yeA0B1kOkAUPnkOQBUh6aT+/83ZsyYtO6666bJkyfnBsCAAQPSo48+moN/jjnmyPf55ptv0uabb55KpVJadNFF07XXXpu22GKL9MEHH6ROnTrNjvcBAEyHPAeA6iDTAaDyyXMA6EAz2y+88MIc6hHi//3vf1OXLl3Sddddlzp37pzDP0S4v//++2nXXXdNzz//fL6ue/fuQh8A2gl5DgDVQaYDQOWT5wDQgYrtDz74YDrssMPy1926dUtDhw5Nd955Z/5+7NixaaONNkqbbLJJmn/++dM+++yTGwbl4AcA2gd5DgDVQaYDQOWT5wDQgYrt7733XlpqqaVqvl9rrbXSG2+8kb+ee+6503777Vcn8KNxEKa3twwAMHvJcwCoDjIdACqfPAeADlRsj31japtvvvnSl19+mb+OJW1iGZs99tijJvhjqZtQ/h4AaHvyHACqg0wHgMonzwGgAxXb6+8BM2XKlPTtt982uF+pVGrZIwMAWow8B4DqINMBoPLJcwCoHjNcdyZG0kWolxsAn3/+eR5pF+K64cOH59unTZuWryv/qyEAAO2HPAeA6iDTAaDyyXMA6EAz2wcMGJBefvnlmu+feuqp1L9///z1yJEj89fLLrtsTdCX/y03AACAtifPAaA6yHQAqHzyHAA6ULF9iy22SH/84x9r9pI599xz0+DBg/P38847b75u0qRJNUE/bty49Mgjj6RRo0a19rEDAM0kzwGgOsh0AKh88hwAOtAy8vvtt19ad91104orrpjGjx+f5p9//rTXXnvl2yZOnJj/jf1k5plnnvz13HPPnQ455JC8FA4A0D7IcwCoDjIdACqfPAeADlRsj0B/7rnn0i233JK6du2atttuu5o9ZWJ0XejWrVt6/PHH89evvvpq6x81AFCIPAeA6iDTAaDyyXMA6EDF9tCjR480ZMiQOtdNmTIlL2cDAFQGeQ4A1UGmA0Dlk+cA0EH2bG9KjLi7/PLLW/ZoAIDZSp4DQHWQ6QBQ+eQ5AHSgYnvnzp3THnvs0bJHAwDMVvIcAKqDTAeAyifPAaADFdsBAAAAAAAAoKOa4Z7t77//fl6+JkbVdenSJf9bvnTq1Cnfp1QqpWnTpqWpU6emb7/9tmZvmSWWWCLNPffcs+N9AADTIc8BoDrIdACofPIcADpQsX355ZfPoV5ENASiUXDPPfekzTbbbFaODwBoAfIcAKqDTAeAyifPAaADFdtff/31PMouRthFmM8xxxw139ceaReigVAebRf/9u3bt7WPHwBoBnkOANVBpgNA5ZPnANCBiu0DBgyYPUcCALQaeQ4A1UGmA0Dlk+cAUD06t/UBAAAAAAAAAEClUWwHAAAAAAAAgJZeRj58+OGH6Yc//GGac845834xcSmVSvkS+8R88803acqUKentt99OPXr0KHoMAMBsIM8BoDrIdACofPIcADpQsb13797pmGOOSV27dk2dO3dOe+21V7r88stT9+7d8/eTJk1Ke++9d24EAADtkzwHgOog0wGg8slzAKgOnUoxVK6gCPtx48alueeeO38fT9GlS5c0atSo1KtXr1TpxowZkxs7o0eProj3M+z5L9r6EACq0g7r9kvVnFvyfObJXipJpfwtA2R6a2S6zK4e8gyoFPK8cc7R4f9o00D1ZddM7dkeIV9beZkbAKByyHMAqA4yHQAqnzwHgMo0U8V2AAAAAAAAAOjIZqrYXn9EnX1jAKDyyHMAqA4yHQAqnzwHgMrUtbl3POWUU/JSNrFXzLfffpvOPPPM1LVr1/z1N99807pHCQC0CHkOANVBpgNA5ZPnANBBiu0R9i+88EKac845c9jvsssu6f33309Tp07NI+zi38GDB6c55pij9Y8YAJgp8hwAqoNMB4DKJ88BoAMV22MJmzvvvLP1jwYAaDXyHACqg0wHgMonzwGgA+/ZDgAAAAAAAAAdmWI7AAAAAAAAABSk2A4AAAAAAAAABSm2AwAAAAAAAEBBiu0AAAAAAAAAUJBiOwAAAAAAAAAUpNgOAAAAAACkfffdN62yyioNrr/44ovTMsssk3r27Jk22mij9Oqrr7bJ8QFAe6PYDgAAAMwynfMAUNluvfXWdN999zW4/tJLL01XXnlleuSRR9Lo0aPTgQcemLbYYov02WeftclxAkB7UtHFdifyAFD55DkAVD6d8wBQ2T7++ON0/PHHpz/84Q91rp80aVI6+uij09VXX52WWmqp1Llz57TTTjul7bffPp199tltdrwA0F5UbLHdiTwAVD55DgCVT+c8AFS2UqmUhgwZks4666y0wAIL1LntscceS0sssURaYYUV6ly/4447pjvuuGM2HykAtD8VWWx3Ig8AlU+eA0Dl0zkPAJUvzssHDBiQttpqqwa3vfnmm/m2+pZddtn07rvvpilTpjT6nJMnT05jxoypcwGAalRxxXYn8gBQ+eQ5AFQHnfMAUNn+9a9/pWuvvbbJwe3jxo1Lffv2bXD9vPPOm8/tx48f3+jjTj/99NS7d++ay+KLL97ixw4A7UHFFdudyANA5ZPnAFD5dM4DQGWbOHFi2nPPPfM2bt27d2/0Pj169EijRo1qcH1c16lTpzTPPPM0+rhjjjkmbwtXvgwfPrzFjx8A2oOKKrY7kQeAyifPAaDy6ZwHgMr34osvpnfeeScNHDgw9enTJ18GDRqUB8HH1zvssEMeDB8D3+uLx8Wg+DnmmKPR5+7WrVvq1atXnQsAVKOKKbY7kQeAyifPAaA66JwHgMq34YYbpgkTJuTz7fLl7rvvTiuuuGL+etiwYWnjjTfO2V0/02+55ZY0ePDgNjt2AGgvuqYKPJEv+/bbb3OnfZzIb7rppmmvvfbKM+Vm5kQ+LgBA65LnAFBdnfO1PfbYY+nggw9Or732Wv4+VqMpd87379+/5n465wGgcsSA9xNOOCENGTIk3XzzzWmhhRZKN910Uy7Exzk+AHR0FVNsdyIPAJVPngNAx6FzHgCqw9ChQ1OXLl3SBhtskEaOHJnWWWeddN9996UFFligrQ8NANpcxRTbm8OJPABUPnkOANVD5zwAVJZYNr48GL62I488Ml8AgCoutgcn8gBQ+eQ5AFQenfMAAAB0NBVdbHciDwCVT54DAAAAAFCJOrf1AQAAAAAAAABApVFsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAqOZie6lUSsOGDUubb755WmihhVK/fv3S4MGD09tvv13nfhdffHFaZpllUs+ePdNGG22UXn311TY7ZgCgLnkOAJVPngNAdZDpANCBiu2jR49O559/fho6dGj68MMP00cffZS+973vpU033TSNHTs23+fSSy9NV155ZXrkkUfy/Q888MC0xRZbpM8++6ytDx8AkOcAUBXkOQBUB5kOALOmUymGrlWI8qF26tSpzvWrrLJKbhCsv/76aZFFFknPPPNMWmGFFWpuP/TQQ9Occ86ZzjrrrGa9zpgxY1Lv3r1zw6FXr16pvRv2/BdtfQgAVWmHdfulSlBpuVUNeS57qSSV8rcMqKxMn115Pqufi8yuHvIMqBSVlOfBOTrMXto0UDmam10VNbM9Ar9+6E+ZMiV99dVX+U0+9thjaYkllqgT+mHHHXdMd9xxx2w+WgCgMfIcACqfPAeA6tBamT558uRcpKh9AYBqVFHF9sZG3cUIuhVXXDGtvfba6c0330wDBgxocL9ll102vfvuu7mR0BjBDwBtR54DQOVrqTwPMh0AKj/TTz/99DwbsHxZfPHFZ8PRA8DsV7HF9q+//joNHjw4h/0tt9ySrxs3blzq27dvg/vOO++8uZEwfvz4Rp9L8ANA25DnAFD5WjLPg0wHgMrP9GOOOSYvu1u+DB8+vNWPHwDaQkUW259//vm0zjrrpLXWWis9/PDDqU+fPvn6Hj16pFGjRjW4f1wXS+HMM888jT6f4AeA2U+eA0Dla+k8DzIdACo/07t165aXoa99AYBq1DVVmLvuuisddNBB6YYbbkgbbLBBndtiOZtrr722wWPeeeedvKzNHHPM0WTwxwUAmD3kOQBUvtbI8yDTAaA6Mh0AOoKKmtn+5ZdfpgMOOCDdd999DUI/bLzxxjnkY6+Y2mLJm1j+BgBoe/IcACqfPAeA6iDTAaADFdv/9re/pe233z6ttNJKjd4eS9accMIJaciQIWnEiBFp6tSp6frrr0/Dhg1LQ4cOne3HCwA0JM8BoPLJcwCoDjIdADpQsT1Gz11yySV5n5j6l1//+tf5PhHw2223XR6F17t373TZZZflUXkLLLBAWx8+ACDPAaAqyHMAqA4yHQBmTadSqVSaxeeoOmPGjMmNhtGjR6devXql9m7Y81+09SEAVKUd1u2XKkGl5VY1fC6yl0pSKX/LAJneGp+LzK4e8gyoFPK8cc7R4f9o00D1ZVdFzWwHAAAAAAAAgPZAsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAAKAgxXYAAAAAAAAAKEixHQAAAAAAAAAKUmwHAAAAAAAAgIIU2wEAAAAAAACgIMV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAIB26r777kuPPvpoWx8GjVBsBwAAAAAAAGhnpkyZkm666aa08847p8UWW6ytD4dGKLYDAAAAAAAAFLDAAgukkSNHFnrMz372szRs2LAG199zzz1plVVWSd26dUtdunRJvXv3Tquvvnpacskl09ChQ9PgwYPTcsst14JHT0tRbAcAAAAAmu3GG29ML7/8clsfBgBAmxg/fnw699xz0xdffNHsx3z77bfpoYceysvB1/fBBx+kPfbYI11xxRVpwoQJ6ZxzzkljxoxJTzzxRHr33XfzY0844YQWfhe0FMV2AAAAGrAfHAD1TZw4MV144YXp4IMPTksttVRbHw4VShsDgEp20UUXpX79+qWjjz662Y959dVXU58+fdKgQYPSuHHjGtz+z3/+M89qX2+99fKs9gMPPDD/27lz5/TnP/85bb755mnZZZdt4XdCS1FsBwAAoIb94AAqw/Dhw/NyorHE6CKLLJJOPvnkNG3atGY9Njp0f/zjH6e+ffvmv/U77bRT+vjjj2tuv+qqq3KH7hxzzJE7ehdaaKG0wgorpBVXXDGdcsopudgej4UitDEAqAYHHHBAnn0+adKkZj9m1VVXzUX2eMxGG23U4PY111wzvfLKK+mpp57Ks9gvuOCCtOmmm+Zi+3nnnZeOP/74Fn4XtCTFdgAAgCorpLzwwgtpt912S0svvXQePf/d7363wVJ19oMDqOylS6MDdsstt0xffvlleumll3LnbOTEjDz99NN5VtVee+2Vlz5966230mabbZY+++yzfPszzzyTlym999578+scccQRuUga94vHdurUKR1++OGz4V3SmrQxAKD9iFz961//mgc0Ri5He+zqq6/Os+i32GKLfDvtl2I7AABAlRVSTj311Fw4if1047EnnnhinkUWHeTBfnAAle1Pf/pTWmONNdJ+++2XunbtmhZeeOF03XXX5b/n8Xe/KVOnTq35+x+5EI/t0aNHLrzH84Vnn302bbLJJmnAgAFpzjnnzLO3omAaTj/99LysaRRPqVzaGADQ/sRgyH/961/p888/T3/7299Sz54986z24447Lj3wwANptdVWS/PNN1/acccdC+0VT+tTbAcAAKiiQkq49dZb0+67755nnEWBJDrTd91113TXXXfl2+0HB1DZbrvttrz0e20LLLBAnmV8//33N/m4uC2K6zFDqimRDdGh+8Ybb+SlTiOPtttuuzRixIicL4ceemiLvhdmP20MAGj/Lr744rTVVlvllWd+9rOfpd///vfpv//9b5prrrnSvvvu29aHRy2K7QAAAFVUSAnlGYi1xfLAvXr1yl/bDw6gsr355pt55nl9UcSM25oSS5JusMEG+d8oekaurLTSSvlvf6lUyvf5/ve/n2cvR4E9liyN/UXPPvvsdMYZZ+SlTctZQuXSxgCA9m3ixIk1s9pja58f/ehHeWWZGDR55pln5i1bImdpH7q29QEAAADQcoWUxlx//fW50zv2e6u/H9zHH3+cfvCDH9gPDqCCRAG8b9++Da6fd95509ixY5t8XCxLGoXQ559/PhfQ119//fTaa6/l5UhjL/Zf/vKX+X577713vpRFVkSBNvLn2muvTaecckr6+uuvc0H+D3/4Q5pnnnla6Z3SGrQxAKD1xEz0GGQ2q7Pat95667TYYovlAZG1n6+8Ygzth/8bAAAAVVRIqX+SH3upxmj4++67L80///w1t9kPDqByxaymUaNGNbg+rou/502JPdgnT56cHn/88bTxxhvn72Mm8vnnn5+X+G5KzGo/5JBDcmH+sMMOy0uOv/XWW+n999/PuUFl0cYAgNbx7LPP5tVePvjgg1ma1R5ts2OPPTZ/H1u2RH5G+y3acZGnkbWxFQztg2I7AABAFRVSyj799NO81Nzrr7+e90+Nju3psR8cQOWIWcnvvvtug+vfeeedtMIKKzT5uOWXXz7169evwUz0WEr+ww8/bPQxMTv59ttvzzOVY3b7XnvtldZee+1cmP3tb3+b7rjjjhZ4R8xO2hgA0Dq6d++e21lzzDHHTD9H5OY222yTFllkkfx9rApz4403poMOOigttNBC6auvvsr3of1QbAcAAKiiQkqIUfTrrbde+ulPf5puueWWRmev1WY/OIDKErOZbr755jrXjRw5Mj333HN5L/ayKG7WNnjw4PTkk0+mN954o871L774YqPLiofIgVhePjqOLWNaHbQxAKBlRNuo9uouq6++evrss8/y8u9Neeyxx9IOO+ww3YL9McccU+e6yM5YYSi28Rk2bFid16TtaQ0DAABUUSEl7LHHHnm24f7779+s17IfHEBlieJ3LCV65ZVX5hwYMWJE2mmnndKRRx6Zl+duahnTJZZYIh199NF5tlTcPnXq1Pzv4Ycfno4//vgGr/PJJ5+kO++8Mx144IH5+2233TZdddVV6dVXX83LjZ988sn5OiqLNgYAtF+RsTGDncqhNQMAAFBFhZTYQzcKIEOGDGnW69gPDqDyxGzihx9+OBdM+/Tpk9ZZZ500cODAvIf2jJYxPemkk9IRRxyRi6YxuziW8T777LPz8t6N7dUeeTT33HPn79dff/183yiwL7XUUmnhhRfOhVcqizYGAEDL0ZIBAABox4WU6BA/9NBDc0Ek9mgrd1g3VUiJZWFjD9W4f33f+c530jPPPNPs/eCi832TTTaxHxxAO7TccsvlZbmbUl7GtDExU708W70pMQt50UUXbTCDeffdd88XKpc2BgBAy6nKYvvw4cPTwQcfnPc9iEbhfvvtl0444QTLEgFABZHnADNXSIkZYlOmTGn2azS1H1xcYFbJc6hcnTp1SkOHDm3rw6CVaGNQlEyHjmfUfRe09SFAs/XZ/JDUVqouCcePH5823XTTvCzRl19+mV566aX01FNP5T2kAIDKIM8BZh/7wdFa5DlAx6aNUT1kOgB0oJntf/rTn9Iaa6yRR9aF2DvquuuuS/37989LI5X3HQIA2i95DgCVT55T6czmqg5tOcsJqoVMB4AONLP9tttuSzvttFOd6xZYYIH03e9+N91///1tdlwAQPPJcwCofPIcAKqDTAeADjSz/c0330wDBgxocP2yyy6bb2vM5MmT86Vs9OjR+d8xY8akSjBh3Ni2PgSAqjRmTLdUCcp5VSqVUrVo73kue6kklfK3LIx68OK2PgRotj4/2r/Fn7PaMn1m8rylM11mV4+2yLMx4yfO9tek5XVug/69v7w3bLa/Jq1j72V3SB09z4NzdOiY5+jaQnT0Nt+YZmZ61RXbx40bl/r27dvg+nnnnTeNHdt46J5++umN7i+z+OKLt8oxAkBriJzr3bt3qgbyHID279et9szVkukzk+dBpgOV8vea6nd4+nnq6HkenKMD0P79utWeeUaZXnXF9h49eqRRo0blfWNqi+si/BtzzDHHpCOOOKLm+2nTpqWvvvoq7zXTqVOnVj9m6ChiFFA0qIcPH5569erV1ocDVSNG1kXgL7LIIqlayPOOR0ZA6/C7VVmqLdNnJs+DTG8+v+PMCj8/zCw/Ox0rz4Nz9I7H7zm0Dr9b1ZnpVVdsj+Vs3n333bTiiivWuf6dd95Je+65Z6OP6datW77U1qdPn1Y9TujIIkQECbSsahktXybPOy4ZAa3D71blqKZMn5k8DzK9OL/jzAo/P8wsPzsdI8+Dc/SOy+85tA6/W9WV6Z1TlRk0aFC6+eab61w3cuTI9Nxzz6XNN9+8zY4LAGg+eQ4AlU+eA0B1kOkA0IGK7b/85S/T448/nq688sq8NM2IESPSTjvtlI488si8RA0A0P7JcwCofPIcAKqDTAeADlRs79u3b3r44YfzSLtYlmadddZJAwcOTCeeeGJbHxp0eLF01EknndRgCSmA+uR5xyMjoHX43aItyfPW53ecWeHnh5nlZ6fjkekdj99zaB1+t6pTp1Ls7g4AAAAAAAAAdNyZ7QAAAAAAAADQ2hTbAQAAAAAAAKAgxXagzbz88svpvvvuK/w4u18AVD8ZAQDFyU8AoKVpXwBMn2I70CJuu+229MMf/rDQY5577rl03XXXFX6tY489Nv36178u/DgA2oaMgJb3zjvvpL333jv94Ac/SLvuumt66qmn6tx+5513pu23377OddOmTUuXXnpp+vGPf5zWWWedtPbaa6c111wzrbrqqmn33XdP//znP2fzuwCmR37SlBEjRqS11lorffe7303rr79+/nv+i1/8oiYfBgwYkL9ed91104MPPtjGR0sl0b6A6qd9Aa1DhnZsXdv6AIDKMG7cuPSb3/wmPf7446lfv37pyCOPTJtssknN7d26dUudO3du1ojGTp061TymS5cudW4/8MAD07Bhw/Jzffvtt/kS9586dWraaaedcvjMOeec+XsA2gcZAbPXRx99lDbeeON00UUX5d+1p59+Og0aNCj9/e9/TxtssEG+T/wudO/evc7jTjvttPTEE0+kq666Ki2yyCI118fv0gMPPJC22Wab9OKLL6aFFlpotr8n6IjkJzMr/h9++eWX6YMPPqj5fx+dtSH+/88111z56/j/Os888zT5PLvttlv+GYgMmZ7zzjsvXX311fm14hI/S/HvlClT0uTJk9MyyyyT7rrrrhZ9j8x+2hdQHbQvYPaToZjZDjRLjMaKk/T4I3/00UenvfbaK/+hL4uwKJ/ch0suuST17Nkzj6hfaaWVUv/+/VOfPn3S8ccfX3OfOeaYo8Hr/PnPf06ff/55+vTTT9P555+fR3t9/fXXacyYMbmRVn4tANoPGQGz10033ZT23XffNHjw4NSjR4+02Wab5c6uv/71r3XuV79DLE74Y+Zj7ZP40LVr17Tlllum73znO+n111+fLe8BkJ/MvPi7HYXut956K73xxhvp3//+d5o4cWLNbbWLKE0VVL755pu8JHAsDTwj8fOz9dZbpxdeeCH/jD7//PN5lmPMtnr11VfTHXfc0YLvjrai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jB49Oo8wXGihhQofGwAdkzyX5wBUB5ku0wGofPJcnkNLUWyHdm7EiBHp8MMPz8urHHPMMenggw9OEyZMSDvssENePmbcuHHpmWeemW7wR0DFfeuHezwmbqs9aqyIxx9/PN15553pscceS4888ki666678vW33XZbHjkXIbn99ttPt9Gx8sor1xxDHE8EdnwdxxtL7pSPs7luvfXWtP/+++cRf0cddVQ655xz0nnnnZfOPvvstMYaa6Rnn302jwxcbLHF0g9/+MN8W2PiOGYk7hPHCQAzIs/lOQDVQabLdAAqnzyX59CSFNuhHYvRXFtssUXaeeed0+abb54OOOCAPKor9lOJ0V+1A7SpcCwH+qqrrpq6d++eLzECLkbnxXIt8f2ZZ55ZOPhj35fBgwenq6++OvXv3z/95S9/STvttFP+N0aoNWdkXLxmjMArLxnTmKIjAGNPl/iMrrnmmvTee+/lY4rP5te//nUeJbfCCiuke++9N7377rv5tu9///uNPk88JhowMeIvRvvFSMIll1wyLbHEEmmRRRbJowDnn3/+3NAAgOmR5/IcgOog02U6AJVPnstzaGn2bId26vXXX08/+clP8nI1v//97/N1EY6xTEuMsFtllVXSSy+9VGdJlQircuCWvy7v0dIcMWps/PjxuUEQ4d3UqL+hQ4em+++/P91www3pRz/6Ub4+loqJUXZ77LFHevnll/OowPJxNCUCfdKkSXk0XixvE8caxxyj7sqXIsE/duzY3MCJ0XS1xfOEeK0xY8bk55tnnnnStttum6976623coMg3n/cN44lRt81NQKvsfcRj23qMwOg45Ln8hyA6iDTZToAlU+ey3NoDYrt0E7FaLXNNtssnX/++XVGoPXs2TPdc8896eGHH26wd0nt4L/kkkvSgQcemMNozjnnzM8RX0eox9dx3wisWDamfCkHZIyg23TTTRs9rj59+uRwPeuss/Jos9piiZi33347h2ntY2pKvP4777yTR7GVg7/2Y2vfrzl22223vMxOvMdu3brVjOCLz2T55ZdPe++9d82yOeXlaOI9x/t48cUX89JAG264YX6u+Izic4vH1h81WF4CqLxMUDznz3/+83T55Zc36zgB6Djked37NYc8B6A9kul179ccMh2A9kae171fc8hzmLFOpSIbMwDtUowSi/1RLrvsspqAin1lJk6cmEeTRXBFkEUIhgipCNpoHHzzzTc5bOPf8j4usVRLBGdLiEDt1atXGjBgQIPbyqEZxxKiERABHY2H5ZZbLt8Wlzj25iyRM6siyEePHp0bDnGJ44rRdxdddFEaOHBgzf1+/OMf50ZVLOkTj4lLHGMsDwQAM0uetwx5DkBbk+ktQ6YD0JbkecuQ53QEZrZDBXj11VfTn/70p/Tcc8+lTz75JAd1hPi8886bVl999Twa78ILL6wTjrE/TFxCLDWzzjrr1IzKK480CzGSLC4zY9SoUemcc85JDzzwQPrf//5XM0ovnj9GA6622mrpF7/4RVp77bUbfXy5IVJWXhImGh3xXmYl7B955JE0bNiw9OSTT6bPPvss77cTrxf7way88sp5OZtoANV+7/H60eiZ0Si/8mcXxzcrnx8AHYs8L06eA9AeyfTiZDoA7Y08L06eQ+P+3zoZQLsUwfW9730vLbHEEunqq69O//nPf9JXX32VgzbCbdddd83Xb7LJJjWBVN9OO+2U95opKy9nM6ti75gI1Ouuuy599NFHuVESl08//TQ9//zz+XVjmZkbb7yxWc9XO1BnxZlnnpn3sfn+97+f/v73v6f//ve/eSRc7C/zz3/+M/3qV79K119/fdp6662b9XzlBk1ZS3x2AHQs8rw4eQ5AeyTTi5PpALQ38rw4eQ5NM7Md2rmbbropbbzxxum4446rc/3cc8+dGwNxWXPNNdNSSy2V3n///dS/f/8GzxFLs5RHsIVY/mZWw3XMmDF5uZqHHnoo9e7du8Htffv2TTvssENuuMQovGgElMXSNRHEMZouji2CNML1vffey7e/8cYbOaSjIRDXx3I7EyZMyPdral+b2qIhdPjhh6dddtmlzvXxGcReNdFgidF08blFwyWOtSlxDI2NsqvfGACA6ZHn8hyA6iDTZToAlU+ey3NoSYrt0M7FviUxUu3UU09NgwYNSksvvXTNUjWxpEyE5B//+Me8z0k0AhoTQRUj68phVQ7q+D5uixCOvWb69OlTs5fLjMSeMBtssEHaeeed069//eu0xhpr5OvKRo4cmRsFN9xwQ7rgggvqPDZGwMXyPCFeL5aEiX9jD5ZYcibeb3nvmAjd8mXxxRfPjYYZicbBeeedl0M+RiguvPDCeT+YeK8xQvG1115Lp59+elprrbWmG/qh/Nr1r4vGCAA0lzyX5wBUB5ku0wGofPJcnkNLUmyHdm777bfP+7789a9/zYEYS8bECLcYJRf7xyy//PJ5/5i//OUvTe5jEkG1+eab58dEuMY+KuU9ZMqNgvI+Nausskqzj+3ee+/NATt06NC81E6MhIuRbOUAj8bANddck4+vthh1F8fQvXv3fN+Wdu6556ZVV101XXvttenQQw/NYV8WI/vitvg8jjrqqBk+V7lBUlt8ZtFQAoDmkufFyXMA2iOZXpxMB6C9kefFyXNoWqdS+TceqFoRVDMK2GgcRBhXo3hv48aNy6Efo+0AoBLJc3kOQHWQ6TIdgMonz+U5lCm2AwAAAAAAAEBBLb+WBAAAAAAAAABUOcV2AAAAAAAAAChIsR0AAAAAAAAAClJsBwAAAAAAAICCFNsBAAAAAAAAoCDFdgAAAAAAAAAoSLEdAAAAAAAAAApSbAcAAAAAAACAghTbAQAAAAAAACAV8/8B2MfULedpS30AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue\n", + "\n", + " ratio_df = mall_df[\"์„ฑ๋ถ„ ์ •๋ณด\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"์„ฑ๋ถ„ ์ •๋ณด ์ข…๋ฅ˜\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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6Of+NEg+JbgL+7FT/3uK9enZP103JcTTM3saUJ8GwaXEeuqX/t3vfhd77rlniTicBsinvus0MCDdF6Rn9/TvpDDmp2R+ame6d0j9BKmPPfWXp8R+ctZZZ8Wdd96Z7xnSQLuUOJ88eXK+50jS/UqhlFgvvP9I9x3peX3QoEHx8ssv58+Daq0AqHB9+/YtaNCgQcHzzz9fYv9rr72W9//ud78rGDlyZKrxUtC4ceO8v7if/vSnBXXr1i2oX79+wZNPPlni2Kmnnlqw8847F71+5plnCqZPn16qDV27di3YbbfdSuxLn5e2//qv/yqz3elYaldxS5cuLdhuu+0KvvWtbxV89tlnJY4NHDgwt/Ptt9/Or8eMGZOvsW571qxZU7DjjjsWXH311eX6jZLC32n77bcveP/990u1ef/998/fdV2XXnppQfPmzQtWrFiRX9944435OnfffXeJ89auXVtw0UUX5WOPP/54uX/Tv/71r/m9636PZcuWFWy99dYFV111VanrAEBx77zzTo4lderUKbj//vtLHEv3AbVq1Sq45ZZbckxJ5917772lYvWBBx5Y0Lp164LFixfnfb17987n7r333kX7kuXLl+dYlu4x2rVrV/Dee+8VHUsxs1OnTgU/+9nPivYdc8wxBa1atSr417/+VeIzH3300RJx9bLLLiuoXbt2wQEHHFDqfuFXv/pV/g5///vf8+vvfve7uX2F7Uyv1+drX/tavnayzTbbFPz4xz8udc6cOXMKxo4du4FfGACqhurUlwAAVcX5559f0LBhw4KXX365xP70/HzUUUflOHfTTTflv2+88UapvuXbb7+94NNPPy3aV9Zz7sY+9yepDz29fuihh0qcN3/+/IJtt9224PTTTy913cJ+7ULpOTrt33PPPfP3KG727NkFjRo1KjjhhBNyv31xJ598ckGzZs1yP8OiRYvyc37qO1/X66+/XjBp0qT878J7k9R38NZbb5U4L927lPW7QXWjjDxUsFSK5Y477sizuNLsr/S6cEulZdLs73vuuafo/DTzq3DUWfFZYakMy89//vNcKrW4NGI8jZpLZdWTb33rWyVGxxVKo+PSzLIlS5aU2J/OLRyZtjFS6bk0my3NJksj14p/nzSiLT1Xp/IwhW1LJWmKf78kjbZP1yj83PL+RkkaLZdms68rjZ5PJW/XLVOXRh2mEYBp5H6SRgh++9vfziP2i0sj9tMIv+LK85t27do1l99NIx2LGz9+fP691v08AFifNKv8xz/+cYl96T4gzVZ77bXXcvnXdE66TyguzSBPZd3SyPlUtq64FJ9SqbdCaXZ7ukYqUZtG02+33XZFx1LMTJVs0qjz5M0338yz5c8///xcVq54vE4z6ffaa68S8TqNvk+j2AtHyhdKI+xTG9Ko+68qjeZftWpViX2puk6a3QcAVVl160sAgKogzUhPz81ptnqqKFNcen5et9JLiqXr9i2nuJtmhlfEc3/qa0/P1anP+bvf/W6J+4H0GamqTFoGZn3Lqq4r3S8UVo8tlCrepYo2aSZ6ivfFPyPNkk9LyaW+gEJpln/hMjWF0jKt3//+90vsS5Vk0z1McWlmfpK+G1RnyshDBfv73/+eO4FTkF43AVs8CBcGxJ/85Celjhd2ipfVcZxKySTLli3LJV8LpcCY1pB55ZVX8lriqYR6ksqqFu9kX7fc+hd58skn898U3NcnldhJUud6erhP5XNSx3rxEvKp874wWV7e3yhJ68eUJd3wXHjhhbkDf/DgwXlfShKk36Aw4ZA6CtJNQf/+/cv13TfmN03ld1IZvnQzkZIgabBBYbI/rX3Xtm3bcn0mADVXemguSyoPl2JPSqYff/zxZZ6THnTTunGpTFthObeUhE5lXteVYlhKrHfr1q3M+4x0j1H8HiCVbk9bWYqv95buA9LAtnWldehSp8WLL74YX0VqQypFl5ZoSWX0U/v33nvvr3RNANhSVLe+BACoClJJ9lRG/phjjtngeankeur7Tc+h6dk9bSnZnJ53K+q5P5V9f+utt/Ig8//+7//OS6muT1o2JpWy35B031BW/E7P+umeo2PHjhvs70/97mkQQipfn16nAYHpd1o3ob6h75a+V5K+G1Rnku1QwQpHiadE79e+9rX1npfWY0k2dE7qJF+f/1epLWL+/Pl5vZS0hksa7b7ffvvlQJvWikkPy+tq165dub9PGsF+2223rfecbbfdtujfqfM7dQykjoLUwZ9md6c1WdIM+eLX3JjfaGPanZIFafRgWjvm8ssvj3r16uVEdxoNmNawSVJyItlll13KvMa6I/PK+5um75zWn7n77rvzTPuUeEiz7dOadgCwsXbYYYf1Hksd3knxmejrSuuyFcbYZEMxNp271VZbbfAeo/BaaV32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gC/ob9qyCi+++GKccsop0b9/f781wGZSk0q1iemb14wZM+K5556LU089tbKbAlAj1JSYLp5vPtOnT4/TTz89unTp4rcG2ExqSjxPxPTN6/3334977703fv3rX1d2UwBqhC+K6TVj0Zhq7r777ot99tknmjVrFrvttlucf/75OeGdvPXWW/HLX/4yvv71r+fje++9d9xzzz0bdd20DkEK2G3bto2WLVvGwQcfHBMmTCg6nq79ve99Lxo3bpzXKqhXr17st99+sd1220Xv3r3j888/j5/97Geb7HsDAJtWup+YNm1a/OhHPyq6twAAytarV69o3rx5qa1hw4bx9NNPlzo/DU4fOnRouT9nwYIFec3Add/73nvvxXHHHZc/s/AZ/Rvf+Ea0adMmevbsGW+++WbuLwAAqvYAuuOPPz4++eSTym4KAP8/yfYq7tprr40rr7wybrvttli8eHE8+eSTuZzB2rVr8/Grr7469txzz3j22Wdj0aJFMWzYsLjoooviL3/5ywavu2LFijzi/bPPPov//d//jY8//jh/1ocfflh0zg9/+MP48Y9/nMsoPPXUU7HVVlvFb3/721yabtddd41BgwZF3bo1qngCAHxpKX6edtppeZBb6iQ/5JBDYvLkyWWe07p162jVqlUcccQROcZ/EQPoAGDzDIRPz93Ft5dffjnP8EtxtVB6Xk/V4MaMGfOlPifNUK9Tp06p/X369Indd989Pvroo3jjjTfyvUI6N90/HHroofleIN1jAABfbQBd6oPfeuutSx1PsfeLLFy4MK644oo8eS69Z5dddsn96KtWrSo6xwA6gKpFsr2Kr4k+ePDg3BF/0EEH5X1pdPvll19e9OB9++23xznnnBPbbrttLnOQOtdTIP6iZPuQIUOiXbt2OTmfbhIK35se1JOUfJ81a1aceeaZOeCnhEDqPEifmzoN/vnPf1qrHQDK4ZhjjsmJ8FSyPXWSn3XWWfnhOnWWJ2nft7/97bxO0L/+9a/ccT5gwICYN2/eBq9rAB0AVJ4bbrghPzenzvkkDZJPVedSTE8d6eWVntHT/UIaJLeuNADv5z//ee6QT0n373//+/kZPd0rjBs3Ls4777wK+U4AUNMH0KWBc+lZed1zUvWZL5LKv6f7gQceeCDPTn/88cfzc3iqeFPIADqAqkWvaRV25513xkknnZRHtK1PWaPdU1De0No5qUxseoCfOHHies/ZZptton379nHzzTdH375945lnnol33303J91Tkj11ypf12QBAaW+//XYexJYGrBVK8TQ9fKdR83vssUdceOGFuVRcGlRXKHWif5HiA+gKpQF0aUsMoAOATSN1pI8ePTpef/31on0p0Z4qzhR2pJdHGpB3yy235KT6r371q1LH0yD8dDxVv0vnpo77dN9w1VVX5ef29NkAQMUMoPuy0pKvxfvN0/N6WhomPe9ff/31eV+K9WkS3foG0KU4D8CWw8z2KiwF3dQhPmrUqNh///3zCLfUcf7oo4+u9z1Tp06NESNGlPlgXijNllu2bFl87Wtfi379+uWAn8rOnnLKKfH+++8XnTd+/Pj461//Gttvv33853/+Z9x///25sz5tJ554YoV/XwCortIMtTQDffbs2SU66P/xj3/EAQcckEfIpwfq8paJKxxAd/HFF2/UALpULv6JJ54oGkCXOugNoAOALz9APlWuSc/MX1UqLZuWdBk+fHheOq4sqW8gDeBLVXDSMjCpk75+/frx4IMP5md7AOCrDaBLg9e+qo2ZHFc4gC7F/9QvkAbQde3a1QA6gC2UZHsVlsq/3njjjXnN1bvvvjvmz5+fy8306NEjXnrppVLnp3XdUxI8zZLr2LHjBq+b1pxJI+bSmjGvvPJKHomfHtJTmdnUEZ+kUXUpsZ/K2aSZ7Snhn0rOXnrppfkB/8gjj4wWLVrkzvp0DQCgbKn8W1oaJsXMNKI9PcSnzvmU7N53333zDPOdd945P2ifeuqpseOOO+ZBcWnwXCr9vj4G0AFA5VizZk0eyJbKvFaEgQMHxtFHH11UmaYsaVm5NDgvddinZ/D0TJ4q3KSl5dJyMmnJmDTILq35+thjj1VIuwCgpg6gS8/a6Tk7lZNPS7h+97vfzZXpyivNVk/XKV5G3gA6gKpFsr0KS+updu7cOcaOHZsT3+l1Wts1rfF6xx13FJ2XStT16tUrrzXzwgsvlLm227rXTevFpLI1aU23lDBPW0rWp4R+8RK3xaV1a95555044YQT4kc/+lFePybdLKQO/WOPPTaWL19e4b8BAFQXPXv2zLPYR44cmZPdaZZ7Guz26aef5oFwKdGeOtkPO+ywXDLu73//e467GypBawAdAFSOv/zlL3mw2z777POVr5XWck3xOSXcyyM9vz/00EN5cF6aFZ8S7XPmzIkrrrgiD9JPz+sAQPkH0KXn4w4dOuQ4n/rE0/P7aaedFkcddVS89tprG33tNGP9W9/6Vu7PT7G6kAF0AFWLZHsVlmanpxlq60oJ+MIytAsXLswj31PwTw/oaSbcF9ltt93y31RStri0RszXv/71EiVui0ud8pdddlle2zV17l9yySW5gz+tQ9O4ceP1JukBoKabNGlSfsBOD+dvvPFGPPzww7lUXEqmp87wNBAuxdY0wC6Nak9xNY2oTzPg//a3v5WYpV6cAXQAUDmuu+66CpvVfu+99+b7grR0XKqGk7YxY8bkpV7Sv9Mst7KkUrPnnntu1KpVKyZPnpyr5zRq1CgPuEvladM+AKD8A+j23nvv/ByfBr+nWJzia3pWT8/0aRb8xiz5luJ0ev8999wTF1xwwQbPN4AOYMsm2V6FpUCa1l9Pa7wWlzrOU3I9SWVl0ki3FHhr1y77/91r164t8TrdIBxxxBF5xF5xadTcm2++WXTtdTvl//3vf+dO+XSzkD4rPdAXX4tmfZ8PADVdmkF+9dVX587v4uu4pzifHuDbtGmT42uanb5uzE4j3tc3EM4AOgDY/FJFuTQTLQ1Q+zLWfUZP67SninWLFi0q2tIyL7/73e/yv48//vhS13jvvffy4L20rmu6h0g8owPAph1Al56zU2J8Q1JcPumkk3LVmrQU7Le//e0vvK4BdABbNk9WVbzcbOp0T6XjU2d5Ki+bZrilEe4pyZ4exlMZmbT26obstddeuQxNcddee22e9ZZmwqX1Z1JZ2bRGbCorm9aOXVdaUzZ1yqeA36lTpzziPgX9VJ72T3/6U77GfvvtV+G/AQBUF2V1eL/77ru55HuKv2mt9RRTi0sd+elBvjCZbgAdAGwZnfLpmfzLxsuyntHLq7BTPg2WSwPlunTpEgMGDMj9BmkgX1qOJu0DACpuAF1KeqfS7oXWfUZP7rrrrjyoPc1UT8/sX8QAOoAtn/8KV2EpkKZAm5LbBx54YC4Lm4J1Cuqp0z11lKebgbQ/PVwX34qXk2/atGkeCVfcnnvumcvO//Wvf43tttsu9thjj2jdunVeQ3Zdad2YuXPn5qR/YbvSzcLEiRNz0n3YsGH5dXrIBwBK+8UvfpHLvD/yyCO5EzxtU6ZMyTPV0qz3hg0bxi233BK/+c1vcom5lStX5jj/05/+NM4444zYdttt83UMoAOAypUGyqVn8hRrv6yyntHLI3XKT5gwIa//WmjUqFG5ben5/vzzz8/P9mlJGgCg/APonnzyyTw7/dVXX80J8AULFuT4mpaFS0nxQmU9o99xxx25sl3qQ98YBtABbPlqFRQOh6oBlixZEs2aNYvFixfnh1cqRkqqp1F4qWQNAJtfTYxv1fE7p/VWU1L7rbfeyg/ynTt3josuuii6detWdE4aCJceqtO6ranMfEq0Dxw4MOrWrZuPH3zwwTkBnx7Ei0sdABdeeGF+CE8P6L169coP/Ot25KcBdKeffnouZVc4Un7WrFm5fHwqHZ+S7ylxX3ytOgAqTnWMbxtS077v5pLifSovf9RRR1V2UwBqpJoY36rjd06D1NKz7zvvvJOT3MWlQeipglwavDZz5sw8QD7Nfk+J8TRhrVBZz+hpQPu6y8IWeu6553KCvvgAukMOOSQn8dNnJGlyXRpQN3Xq1Lys3A033BDf+973NsEvAMCSjYxvku0AUMXVxPhWE7/z5mAAHUDlqmnxraZ9XwBqhpoY32rid94cDKADqBrx7f9NgwIAoMbzAA8AAABbBgPhAaoGa7YDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5WbO9HMa+8FFlN4EKdsI3t63sJgCwmYnn1ZOYDlDziOnVj3gOUPOI59WTmA7UJGa2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAABFevXqFc2bNy+1NWzYMJ5++ul8ztq1a+OKK66Itm3bRrNmzaJbt24xZ86cym46AAAAbFaS7QAAAECR++67LxYtWlRie/nll6Np06ax33775XMGDhwY06ZNi1deeSUWLFgQXbp0iSOPPDJWrFhR2c0HAACAzUayHQAAANigG264Ic4888w8u33evHlx8803x9133x2tW7eOevXqxXnnnRcdO3aMESNGVHZTAQAAYLORbAcAAADWa/HixTF69Ojo27dvfj1hwoQ44ogjcmn54nr27Bnjx4+vpFYCAADA5le3Ej4TAAAAqCLuvPPOOOaYY2L77bfPr6dPnx4dOnQodV779u3zsfVZuXJl3gotWbJkE7UYAAAANg8z2wEAAIAyrVmzJpeM//Wvf120b9myZdGiRYtS57Zs2TKWLl263msNGTIkmjVrVrTttNNOm6zdAAAAsDlItgMAAABl+stf/hJf+9rXYp999ina17hx41i0aFGpc9O+Jk2arPdaAwYMyCXpC7e5c+dusnYDAADA5qCMPAAAAFCm6667Lvr3719iXyohP2XKlFLnzpw5Mzp16rTea9WvXz9vAAAAUF2Y2Q4AAACU8sILL8QHH3wQxx57bIn9Rx99dEyaNKnUmuvjxo2L7t27b+ZWAgAAQOXZopLt9913Xy5Nl9Zu22233eL888+PgoKCfGzt2rVxxRVXRNu2bfPxbt26xZw5cyq7yQAAAFBtZ7X369cvatcu2XWwyy67xCmnnBJ9+vSJhQsXxqpVq+Laa6+NGTNmxBlnnFFp7QUAAIAam2xPD+ZXXnll3HbbbXnttieffDKv9ZaS7MnAgQNj2rRp8corr8SCBQuiS5cuceSRR8aKFSsqu+kAAABQrbz77rsxefLkOPXUU8s8fsMNN+SS8XvuuWe0atUqnnjiiXj00UejQYMGm72tAAAAUKPXbE/rug0ePDjeeOONaNOmTd63ww47xOWXX57/PW/evLj55pvzTPbmzZvnfeedd148/vjjMWLEiOjbt2+lth8AAACqkx133DE++uij9R6vV69efo5PGwAAANRUW8TM9jvvvDNOOumkokT7uiZMmBBHHHFEUaK9UM+ePWP8+PHrve7KlSvzGnLFNwAAAAAAAACoFsn2Z599Ng455JAYNWpU7L///rkE3cEHH5xL0CXTp0+PDh06lHpf+/bt87H1GTJkSF7fvXDbaaedNun3AAAAAAAAAKBm2CKS7R9++GHceOONeQb73XffHfPnz4/+/ftHjx494qWXXoply5ZFixYtSr2vZcuWsXTp0vVed8CAAXn998Jt7ty5m/ibAAAAAAAAAFATbBFrtm+11VbRuXPnGD58eNG+4447Lv7+97/HHXfcEY0bN45FixaVel/a16RJk/Vet379+nkDAAAAAAAAgGo3s71jx47Rrl27UvtTAn727Nm5hPysWbNKHZ85c2Z06tRpM7USAAAAAAAAALagZHsqFz9ixIhYsWJFif0vvvhiTrQfffTRMWnSpFiyZEmJ4+PGjYvu3btv5tYCAAAAAAAAUNNtEcn2nj17xi677JJLx6eZ7KtWrYrRo0fHmDFjol+/fvnYKaecEn369ImFCxfm49dee23MmDEjzjjjjMpuPgAAAAAAAAA1zBaRbK9Tp048/PDDuST8gQceGC1atIi77rorJk+eHO3bt8/n3HDDDfn4nnvuGa1atYonnngiHn300WjQoEFlNx8AAAAAAACAGmaLSLYnW2+9dVx33XXxwQcfxPLly2PKlCmxzz77FB2vV69eDB48OObPn5/LyY8fPz7atm1bqW0GAAAAAIAtTa9evaJ58+altoYNG8bTTz+dz1m7dm1cccUVuZ+9WbNm0a1bt5gzZ05lNx0AqpQtJtkOAAAAAAB8dffdd18sWrSoxPbyyy9H06ZNY7/99svnDBw4MKZNmxavvPJKLFiwILp06RJHHnlkrFixorKbDwBVhmQ7AAAAAABUc2mp1jPPPDPPbp83b17cfPPNcffdd0fr1q1zZdnzzjsvOnbsGCNGjKjspgJAlSHZDgBUmLQczGmnnZZL0KXydIccckhMnjy5xDnDhg2LXXfdNZo0aRKHHnpovPbaa5XWXgAAAKgJFi9eHKNHj46+ffvm1xMmTIgjjjgiP7sX17Nnz7yEKwCwcSTbAYAKc8wxx0TLli1jxowZ8dFHH8VZZ50Vxx13XLzxxhv5+PDhw2PkyJExZcqU/KB/9tlnR9euXXOSHgAAANg07rzzzvzMvv322+fX06dPjw4dOpQ6r3379vnYhqxcuTKWLFlSYgOAmkqyHQCoEG+//XbMmjUrhg4dmmetpxJ0J598ch4p//TTT+c13y6++OIYNWpUtGvXLmrXrh29evWKHj165PcAAAAAFW/NmjW5ZPyvf/3ron3Lli2LFi1alDo3DaBfunTpBq83ZMiQaNasWdG20047bZJ2A0BVINkOAFSI9ECeEuqzZ88u2pdmr//jH/+IAw44IKZOnRo777xzdOrUqcT7lKgDAACATecvf/lLfO1rX4t99tmnaF/jxo1j0aJFpc5N+9IA+g0ZMGBAft4v3ObOnbtJ2g0AVUHdym4AAFA9pHXeBg8enNdpT6Plt9tuu7w+++WXXx777rtvXHfddestUZdmxK9evTrPhl9fibq0FVKiDgAAADZOeh7v379/iX3p+Twt8baumTNnlhokv6769evnDQAwsx0AqEBplnqaxZ7WZb///vvzLPfXX389Pv300w2WqCsoKIjly5ev97pK1AEAAED5vfDCC/HBBx/EscceW2L/0UcfHZMmTSo1mH3cuHHRvXv3zdxKAKi6JNsBgAqRHtK/9a1vxWmnnRZvvPFGPPzww7mE/DvvvJPXZd9QibpatWpFo0aN1nttJeoAAADgy81q79evX9SuXTIVsMsuu8Qpp5wSffr0iYULF8aqVavi2muvjRkzZsQZZ5xRae0FgKpGsh0AqBCXXnppXH311fHDH/6wxKz1ESNG5ER8+ncqF19WibpUSn59JeSTVJ6uadOmJTYAAABg/d59992YPHlynHrqqWUev+GGG3LJ+D333DNatWoVTzzxRDz66KPRoEGDzd5WAKiqJNsBgAqz7kj5wof7lCw/4YQTcmJ93YS7EnUAAABQ8Xbcccf46KOPcqW5sqRB74MHD4758+fncvLjx4+Ptm3bbvZ2AkBVJtkOAFSIX/ziF3HeeefFI488ksvPpW3KlClx/PHH51nvqUz8oEGDonfv3jFv3rxYs2ZNjBkzJsaOHRv9+/ev7OYDAAAAAEC51C3f6QAAZUtl6Zo1axaXX355nHjiiXmWe+fOnWPo0KHRrVu3fE5KqtepUycOOeSQWLBgQRxwwAExceLEaN26dWU3HwAAAAAAykWyHQCoMGkWe9o25IILLsgbAAAAAABUZcrIAwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAKXcd999sc8++0SzZs1it912i/PPPz8KCgrysbVr18YVV1wRbdu2zce7desWc+bMqewmAwAAwGYl2Q4AAACUcO2118aVV14Zt912WyxevDiefPLJaNKkSU6yJwMHDoxp06bFK6+8EgsWLIguXbrEkUceGStWrKjspgMAAMBmU3fzfRQAAACwpZs5c2YMHjw43njjjWjTpk3et8MOO8Tll1+e/z1v3ry4+eab80z25s2b533nnXdePP744zFixIjo27dvpbYfAAAANhcz2wEAAIAid955Z5x00klFifZ1TZgwIY444oiiRHuhnj17xvjx4zdTKwEAAKDySbYDAAAARZ599tk45JBDYtSoUbH//vtHq1at4uCDD45HH300H58+fXp06NCh1Pvat2+fj63PypUrY8mSJSU2AAAAqMqUkQcAAACKfPjhh3HjjTfGdtttF3fffXdOov/tb3+LHj165FLxy5Yty8fW1bJly1i6dOl6rztkyJCiUvQAAABQHZjZDgAAABTZaqutonPnzjF27NjYfffd8+vjjjsuzjrrrLjjjjuicePGsWjRolLvS/uaNGmy3usOGDAgFi9eXLTNnTt3E38TAAAA2LQk2wEAAIAiHTt2jHbt2pXanxLws2fPziXkZ82aVer4zJkzo1OnTuu9bv369aNp06YlNgAAAKjKJNsBAACAIqlc/IgRI2LFihUl9r/44os50X700UfHpEmTSq25Pm7cuOjevftmbi0AAABUHsl2AAAAoEjPnj1jl112yaXj00z2VatWxejRo2PMmDHRr1+/fOyUU06JPn36xMKFC/Pxa6+9NmbMmBFnnHFGZTcfAAAANhvJdgAAAKBInTp14uGHH84l4Q888MBo0aJF3HXXXTF58uRo3759PueGG27Ix/fcc89o1apVPPHEE/Hoo49GgwYNKrv5AAAAsNnU3XwfBQAAAFQFW2+9dVx33XV5K0u9evVi8ODBeQMAAICaysx2AAAAAAAAACgnyXYAAAAAAAAAKCfJdgAAAAAAAAAoJ8l2AAAAAAAAACgnyXYAAAAAAAAAqIrJ9jPPPDOaNGkSzZs3L7Gde+65Jc4bNmxY7LrrrvncQw89NF577bVKazMAAAAAAGzJ7rvvvthnn32iWbNmsdtuu8X5558fBQUF+djatWvjiiuuiLZt2+bj3bp1izlz5lR2kwGgStkiku2rV6+Oyy67LBYtWlRiu/HGG4vOGT58eIwcOTKmTJkSixcvjrPPPju6du0aH3zwQaW2HQAAAAAAtjTXXnttXHnllXHbbbflPvUnn3wyT2RLSfZk4MCBMW3atHjllVdiwYIF0aVLlzjyyCNjxYoVld10AKgytohk+xdJwf3iiy+OUaNGRbt27aJ27drRq1ev6NGjRwwdOrSymwcAAAAAAFuMmTNnxuDBg2Py5Mlx0EEH5X077LBDXH755VGnTp2YN29e3HzzzXH33XdH69ato169enHeeedFx44dY8SIEZXdfACoMqpEsn3q1Kmx8847R6dO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ULnee++9mDFjRuy1115x2GGH5cT6ugn3cePGRffu3SutjQAAALC5SbYDABXiww8/jBtvvDHPYL/77rvzzLf+/ftHjx494qWXXtrg+q5pHdgNSWVn0xrwhdvcuXM34TcBgJrtwgsvjGuvvTY++uijWLt2bY7jab32s846K89uT2XiBw0aFL17987LxKxZsybGjBkTY8eOzbEfAAAAagprtgMAFWKrrbaKzp07x/Dhw4v2HXfccfH3v/897rjjjg2u79qkSZMNXjuVnU0bALDppST69ddfH/vuu28sXLgwJ9jPOeecOPvss4vOSUn1OnXq5Ko2CxYsiAMOOCAmTpwYrVu3rtS2AwAAwOYk2Q4AVIiOHTtGu3btSu1PCfh77703jj322JgyZUqp46kMbadOnTZTKwGAL5JKxY8YMeILz7vgggvyBgAAADWVMvIAQIVI5eJTx/yKFStK7H/xxRfzWu1HH310TJo0KZYsWVLiuPVdAQAAAACoiiTbAYAK0bNnz9hll11y6fjZs2fHqlWrYvTo0XkN1379+uVjp5xySvTp0yeXpE3H03qwM2bMiDPOOKOymw8AAAAAAOUi2Q4AVIi0buvDDz+cS8IfeOCB0aJFi7jrrrti8uTJ0b59+3zODTfckI/vueee0apVq3jiiSfi0UcfjQYNGlR28wEAAAAAoFwk2wGACrP11lvHddddFx988EEsX748r9G+zz77FB2vV69eDB48OObPn5/LyY8fPz7atm1bqW0GAACA6ubMM8+MJk2aRPPmzUts5557bonzhg0bFrvuums+99BDD43XXnut0toMAFVR3cpuAAAAAAAAUHFWr14dl112WVx44YXrPWf48OExcuTIPFB+5513jvvvvz+6du0aL730UrRp02azthcAqioz2wEAAAAAoAZZsWJFXHzxxTFq1Kho165d1K5dO3r16hU9evSIoUOHVnbzAKDKkGwHAAAAAIAaZOrUqXk2e6dOnUrs79mzZ17ybUNWrlyZl4YrvgFATSXZDgAAAAAA1cy0adPi6KOPjm233TbPXk/ruC9cuDAfmz59enTo0KHUe9q3bx+zZs3KZejXZ8iQIdGsWbOibaeddtqk3wMAtmSS7QAAAAAAUI3sscceuTR8Wrd9/vz58fTTT8fSpUujW7duUVBQEMuWLYsWLVqUel/Lli3z8eXLl6/32gMG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1KT4piYNAAAAsNFSmfhBgwblUrfz5s2LNWvWxJgxY2Ls2LHRv3//ym4eAAAAbDZfmGyfNWtWrF279ktd/J133vlS7wMAKpZ4DgDVw5YS01NS/fjjj49DDjkkj/S/4447YuLEidG6desK+wwAqK62lHgOAGyGZPuUKVNiv/32i+eee26jL7py5cr43e9+l9dyA/iq3n///bjuuusquxlQpYnnAFA9VEZMP+yww4pKyK+71uzs2bNj2bJl8fjjj0fnzp2/1PUBoKaprGf0M888M/bcc89S+4cNGxa77rprNGnSJA499NB47bXXvvRnAEBN84XJ9p///Oc5iP/4xz+OY445Ju6+++745JNPyjz37bffjiuvvDJ22WWXePPNN2PatGmbos1ADTJ9+vQ8Y2Z9/90BNo54DgDVg5gOAFVfZcTzBx98MFehWdfw4cNj5MiReQBAWpP27LPPjq5du8YHH3zwpT4HAGqajVqzvVu3bjFjxozYe++947zzzottt902tt9++9hnn33ySLf0d5tttomvf/3rMXny5Ljnnnvi3nvvjZYtW276bwB8Zc8880z07Nkz2rRpE02bNo2DDz44pk6dusGSkUOHDi335/z3f/93/u/Jut5777047rjjonnz5lG7du2oV69efOMb38jtSe1KDxLnn39+uT8PKEk8B4DqQUwHgKpvc8bz+fPnx8CBA+Oaa64psX/FihVx8cUXx6hRo6Jdu3a5X65Xr17Ro0ePL9X3BwA1Ud2NPbFx48YxePDguOyyy+Kpp57KI+hSaecUkFPQ79SpU3z3u9+Nr33ta5u2xUCF69evX5xzzjlx1113xVZbbRUTJkzIN9WplFWHDh2KzktrSb388ssxZsyY/BBQHu+++26+Sd96661LHevTp08unXX//ffnNauOOOKIOP300+NXv/pVbld62EiJeOCrE88BoHoQ0wGg6tsc8bygoCB69+4dV199dTRq1KjEsTTZZuedd86fU1ya/JL669J7AIAKSrYXql+/fl4XxvqtUH2kG+t0c18olW2fNGlSPPLII0XJ9lRGascdd4zVq1fnrTy+/e1vx4svvhhr1qyJH/zgB6WOP/vss3H77bfnGe277757fP/73486derEvHnzYty4cXmUL1CxxHMAqB7EdACo+jZlPE+z2VP/XipXv24ly7R8Y/GJNoXat2+fJ8SkPsDUX1fW+vFpK7RkyZIKbzcAVKsy8kD1VjzRXuizzz4rMdq1WbNmsXTp0jyy9pRTTinX9Z9++un8vjvuuKPM4wcddFDccsstsWrVqvjHP/6RR/KmtaGuuuqq6Nu3b/5sAAAAAGDjvfrqqzF69Oj1loRftmxZtGjRotT+VKo+zYhfvnx5me8bMmRI7q8r3HbaaacKbzsAVBWS7UAJCxYsiOuuuy5eeumlXDJqc0jrQr399tv5xjyVtUqz3NOI3gcffDCXuAcAAAAANl6aSJNKwY8cOTIaNmy43gk4ixYtKrU/7atVq1apsvOFBgwYkKtgFm5z586t8PYDQLUtIw9UTx07doz33nsvj1ht0KBB/OEPf8h/N4cddtghl4svrnC99vRgcNppp8WUKVNyMj6Vvvre9763WdoFAAAAAFVRWtJx5syZcfjhhxft+/zzz3NfW/PmzXPJ+lNPPTXPfF9Xel8qJV9WCfkkTZJJGwAg2Q78/9566638N62rntZrSsnu119/PYYNG7bZ2zJ//vx46KGHcjtOOOGEaNeuXcyZMycee+yx6NGjR7zxxhvRtm3bzd4uAAAAAKgKvvOd78Snn35aYl9asz1Nbkl9fkmadJMS62l99t12263ovDQppnv37pu9zQBQFSkjD5RQp06d2HPPPfMa6vfdd1+ltCGt1X7uuefmclWTJ0/O60qlslU//OEP8/ruaR8AAAAA8OWl/rZBgwblZR3nzZuXJ+GMGTMmxo4dG/3796/s5gFAlWBmO1CmdIPdrFmzcr1n7dq1Ubv2VxvDk0rZP/zww/Hmm2/m6yUp6V58MMBX/QwAAAAAIHJSPfW3HXLIIbFgwYI44IADYuLEidG6devKbhoAVAkyVkAce+yxuWz7ihUr8tpNjz/+eJx55plx6aWXlus6e+21VwwZMqRCZrVvvfXW0bhx47x+1IABA2LVqlUxadKk+Pvf/573AQAAAAAb77DDDisqIV/cBRdcELNnz45ly5blfsHOnTtXSvsAoEYl21NC7pFHHqnY1gCVol+/fnHXXXfFjjvumEetXnLJJXHrrbfG6aefXq7rNG3aNJef+iqz2idMmBBnnXVW0b5Ro0bFu+++G9ttt12cf/75cf/998f222//pT8DKEk8B4DqQUwHgKpPPAeAGlRG/tNPP40TTjghli5dWrEtAja7NFO8PLPF//SnP5W5/7nnntvg+/r06ZO39fn3v/+dk/wNGzYs2temTZt48MEHN7ptQPmI5wBQPYjpAFD1iecAUE1ntn/22WfxwAMPxF//+tdYs2ZN3rfVVltF3brrz9VPnz694loJ1AgHHXRQHHXUUZXdDKi2xHMAqB7EdACo+sRzAKghM9uXLFkS3/zmN2PlypX5BqBDhw553ZYU+OvVq5fPSWsppwRZQUFBtG3bNkaPHh1du3aNd955J2rVqrU5vgcAsAHiOQBUD2I6AFR94jkA1KCZ7bfccksO6imIpxLPderUiXvuuSdq166dg3+Sgvvbb78dJ510Urzwwgt5XyoDLegDwJZBPAeA6kFMB4CqTzwHgBqUbH/00UfjvPPOy/+uX79+9O/fPx5++OH8Oq0dc+ihh8b3vve9aNWqVZxxxhn5xiApvuYyAFC5xHMAqB7EdACo+sRzAKhByfZ//etf0a5du6LX++23X7z55pv531tvvXX84he/KBHw081BsqG1ZQCAzUs8B4DqQUwHgKpPPAeA6uMLo3NaN6a4bbbZJj7++OP871TSJpWxSYYNG5b/plI3SeGNAFDaook3VXYTqGDNj/pVZTcBNkg8B4DqQUwHgKpPPAeAGjSzfd01YFavXh2ff/55qfMKCgoqtmUAQIURzwGgehDTAaDqE88BoAYl29NIuuJB/cMPP8wj7QpvCubOnRtz5syJtWvX5n2Ff8tzI/DMM89Ez549o02bNtG0adM4+OCDY+rUqSXOSde94oorom3bttGsWbPo1q1b/lwA4IttjngOAGx6YjoAVH3iOQDUoGR7hw4d4pVXXil6/fTTT8duu+2W/71gwYL87/bt2xcF+sK/hTcAG6Nfv37RtWvXePvtt3O5nIsuuih69OgRM2fOLDpn4MCBMW3atNyW9LldunSJI488MlasWFG+bwwANdDmiOcAwKYnpgNA1SeeA0ANSranJPi1115btJbM9ddfH927d8+vW7ZsmfelhHdhoF+2bFlMmTIlFi1atNGNSLPY+/TpE40aNYp69erF8ccfHz/+8Y/jkUceycfnzZsXN998c9x9993RunXrfM55550XHTt2jBEjRnzZ7w4ANcbmiOcAwKYnpgNA1SeeA0ANSrb/4he/yKPsdt999/j617+e14459dRT87HPPvss/037UqI82XrrreNXv/pVLoWzsRo3blxq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WbN44okn4ogjjogGDRpEw4YN4+KLL877p02bFitWrMivR40aFe3atYvatWtHr169okePHjF06NDKbj4AAAAAAAAANcwWkWyvVatW3opbvXp1LFy4MJo2bRpTp06NnXfeOTp16lTinJ49e8b48eM3c2sBAAAAAACgavr0009j8ODB8fnnn1d2U6DK2yKS7WWt4d6vX7/YfffdY//994/p06dHhw4dSp3Xvn37mDVrVk7Ml2XlypWxZMmSEhsAAAAAAADURP/+97/jpz/9acyYMSPq1q1b2c2BKm+LS7Z/8skn0b1795xgHzduXN63bNmyaNGiRalzW7ZsmRPzy5cvL/NaQ4YMyaXoC7eddtppk7cfAAAAAACAmivlrsaOHRtHHXVUbLfddrHtttvm3Ndbb71V5vm33nprnHPOOeX+nDfffDP23HPPUvuXLl0ap556arRq1SovzZyS6um87bffPn70ox/F3/72t7j00ku/1HcDtuBk+wsvvBAHHHBA7LfffvHYY49F8+bN8/7GjRvHokWLSp2f9qXy840aNSrzegMGDIjFixcXbXPnzt3k3wEAAAAAAICaK+Wkbrzxxujfv3/Mnj075syZEwcffHB06dIlJ8KLSwn42267rdyfsWDBgvj9739f5rELL7ww1q5dm/Ni6bPTMs0/+MEP4r333ouTTjopTjnllNhtt92+9PcD/s8WUx9iwoQJ0bdv37j33nvjkEMOKXEslZAfPXp0qffMnDkzl5KvV69emdesX79+3gAAAAAAAGBzSNWWn3jiiTxhtNDFF1+cc13Tpk2LI444Iu9LFZk/+uijvHb6d7/73Y2+fkqYP/jgg7FmzZoyl2F+9tln46abboqGDRvGjjvuGMcff3ysWLEir9V+/fXXx5NPPllB3xTYIma2f/zxx3HWWWfFxIkTSyXak8MOOywn1tP67MWlMvOp7AYAAAAAAABsCVKSvXiiPVm9enUsXLgwmjZtWrQvzTxPSfCBAweW6/r33HNPfPbZZzFp0qQyjx900EExfPjwvAxzmlmfEvOpfHyaQZ9K2++6665f8psBW+TM9gceeCB69OgRnTt3LvN4KhM/aNCg6N27d9x///15fYs///nPeb2LF198cbO3FwAAAAAAADZ2Dfd+/frF7rvvHvvvv/8m/7xrrrkmf97Xv/71nNxPyfxvfOMb0bNnz3jqqac2+edDTbJFzGxPM9Zvv/32vDb7uttvfvObfE5a1yKVuUgz31P5jTvuuCPPhG/dunVlNx8AAAAAAABK+eSTT3KV5unTp+eKzZtDSrCPHDky5s+fHzNmzIiTTz45z2o/+uijo1WrVnHmmWfm/FrHjh3z8s5AFZ/ZPnTo0Lx9kQsuuCBvAAAAAAAAsCV74YUX4sQTT4xTTjklV3CuXbty5sCmkvM33nhjPP3003HhhRfGhx9+mJdvfvPNN+OYY47JSfd99923UtoGVd0WkWwHAAAAAACA6mLChAnRt2/fPHM8VW2uTGlWe7du3WKnnXbK67c//vjj0bx58/jWt76VS8untkq2w5cj2Q4AAAAAAAAV5OOPP46zzjorJk2aFJ07d/5Ka73XqlWrQma1P/PMM0XXLD7Dvk6dOpU24x6qA//rAQAAAAAAgArywAMPRI8ePb5Soj1Js9F/8YtffKVrDBs2LH74wx9G27Zt8+vUroEDB8ann34aL7/8cvz5z3/Ox4EvR7IdAAAAAAAAKsisWbPi9ttvj8aNG5fafvOb32z0dZo0aZLf81Vmtd90000xYMCAon1Dhw7NJeS/9rWvxQknnBA333xz7L333l/6M6CmU0YeAAAAKJLKSo4bNy7uvPPOePXVV2PNmjV5Lcc//vGP0bFjxxIzZNK+jz76KPbZZ5+45ZZbYq+99qrUtgMAwJYgJbTTtrF++9vflrn/vvvu2+D7DjvssHj99dfXe/zf//53DB48OLbffvuifSl5P2LEiI1uG7BhZrYDAAAARRYvXpzXdOzfv3/Mnj075syZEwcffHB06dIlli5dms8ZPnx4jBw5MqZMmZLPP/vss6Nr167xwQcfVHbzAQCA/1+nTp2iV69eld0MqNYk2wEAAIAizZo1iyeeeCKOOOKIaNCgQTRs2DAuvvjivH/atGmxYsWK/HrUqFHRrl27qF27du7AS2s/lmf2DgAAAFR1ku0AAABAkVq1auWtuNWrV8fChQujadOmMXXq1Nh5553zLJnievbsGePHj9/MrQUAAIDKI9kOAAAAbHAN9379+sXuu+8e+++/f0yfPj06dOhQ6rz27dvHrFmzcmK+LCtXrowlS5aU2AAAAKAqq1vZDQAAAAC2TJ988kn07t07r9X+l7/8Je9btmxZtGjRotS5LVu2zIn55cuXR/PmzUsdHzJkSFx++eWbpd0AANQsiybeVNlNoII1P+pXld0E2ChmtgMAAAClvPDCC3HAAQfEfvvtF4899lhRAr1x48axaNGiUuenfan8fKNGjcq83oABA2Lx4sVF29y5czf5dwCAmioNgBs7dmwcddRRsd1228W2224b3bt3j7feeqvEecOGDYtdd901mjRpEoceemi89tprldZmAKiKJNsBAACAEiZMmBAnnHBCjBo1Ki677LKoXfv/ug9SCflULn5dM2fOzKXk69WrV+Y169evn9d8L74BAJtGGth24403Rv/+/WP27NkxZ86cOPjgg6NLly65Yk0yfPjwGDlyZEyZMiWff/bZZ0fXrl3jgw8+qOzmA0CVIdkOAAAAFPn444/jrLPOiokTJ8YhhxxS6vhhhx2WE+vrJtzHjRuXZ8wBAJWvWbNm8cQTT8QRRxwRDRo0iIYNG8bFF1+c90+bNi1WrFiRX6eBde3atcsD63r16hU9evSIoUOHVnbzAaDKkGwHAAAAijzwwAO5o71z585lHk9l4gcNGpTXcp83b16sWbMmxowZk0vVptlzAEDlS0u7pK241atXx8KFC3N1malTp8bOO+8cnTp1KnFOz549Y/z48Zu5tQBQdUm2AwAAAEXSjPXbb789r82+7vab3/wmn5OS6scff3ye+Z5myN1xxx15Jnzr1q0ru/kAwHrWcO/Xr1/svvvusf/++8f06dPz0jDrSkvCpHuBlJhfn5UrV8aSJUtKbABQU9Wt7AYAAAAAW45UOnZjysdecMEFeQMAtmyffPJJrkiT1mr/y1/+kvctW7YsWrRoUercli1b5sT88uXLo3nz5mVeb8iQIXH55Zdv8nYDQFVgZjsAAAAAAFRDL7zwQhxwwAGx3377xWOPPVaUQE8VaxYtWlTq/LQvlZ9Py8asz4ABA2Lx4sVF29y5czfpdwCALZmZ7QAAAAAAUM1MmDAh+vbtG/fee29e+qW4VEJ+9OjRpd4zc+bMXEq+Xr16671u/fr18wYAmNkOAAAAAADVyscffxxnnXVWTJw4sVSiPTnssMNyYj2tz17cuHHjonv37puxpQBQtUm2AwAAAABANfLAAw9Ejx49onPnzmUeT2XiBw0alNdynzdvXqxZsybGjBkTY8eOjf79+2/29gJAVSXZDgAAAAAA1UiasX777bfntdnX3X7zm9/kc1JS/fjjj88z35s1axZ33HFHngnfunXrym4+AFQZ1mwHAAAAAIBqZOjQoXn7IhdccEHeAIAvx8x2AAAAAAAAACgnyXYAAAAAAAAAKCfJdgCgQhQUFMTYsWPjqKOOiu222y623Xbb6N69e7z11lslzhs2bFjsuuuu0aRJkzj00EPjtddeq7Q2AwAAAADAlyXZDgBUiMWLF8eNN94Y/fv3j9mzZ8ecOXPi4IMPji5dusTSpUvzOcOHD4+RI0fGlClT8vlnn312dO3aNT744IPKbj4AAAAAAJSLZDsAUCGaNWsWTzzxRBxxxBHRoEGDaNiwYVx88cV5/7Rp02LFihX59ahRo6Jdu3ZRu3bt6NWrV/To0SOGDh1a2c0HAAAAAIBykWwHACpErVq18lbc6tWrY+HChdG0adOYOnVq7LzzztGpU6cS5/Ts2TPGjx+/mVsLAAAAAABfjWQ7ALDJ1nDv169f7L777rH//vvH9OnTo0OHDqXOa9++fcyaNSsn5tdn5cqVsWTJkhIbAAAAAABUJsl2AKDCffLJJ9G9e/ecYB83blzet2zZsmjRokWpc1u2bJkT88uXL1/v9YYMGZLL0RduO+200yZtPwAAAAAAfBHJdgCgQr3wwgtxwAEHxH777RePPfZYNG/ePO9v3LhxLFq0qNT5aV8qP9+oUaP1XnPAgAGxePHiom3u3Lmb9DsAAAAAAMAXqfuFZwAAbKQJEyZE37594957741DDjmkxLFUQn706NGl3jNz5sxcSr5evXrrvW79+vXzBgAAAAAAWwoz2wGACvHxxx/HWWedFRMnTiyVaE8OO+ywnFhP67MXl8rMp5LzAAAAAABQlUi2AwAV4oEHHogePXpE586dyzyeysQPGjQoevfuHfPmzYs1a9bEmDFjYuzYsdG/f//N3l4AAAAAAPgqJNsBgAqRZqzffvvteW32dbff/OY3+ZyUVD/++OPzzPdmzZrFHXfckWfCt27durKbDwAAAAAA5WLNdgCgQgwdOjRvX+SCCy7IGwAAAAAAVGVmtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAAAAAAAAQDlJtgMAAAAAAABAOUm2AwAAAAAAAEA5SbYDAACbxfvvvx/XXXddZTcDAAAAACqEZDsAALDJTZ8+PY4//vj45JNPKrspAAAAAFAh6lbMZQAAgC1N69at480334xWrVqVefzWW2/Nx2+++eYvvNaOO+4Yy5YtK7GvoKAgVq9eHZ9++ml+/d5778XZZ58djz/+eCxZsiTq1KkTe+yxR97fpk2bmDNnTvz3f/93BX07AAAAAKhctbfUTsEFCxaU2j9s2LDYddddo0mTJnHooYfGa6+9VintAwCALdny5cvj+uuvj48++mi957z11ltx2223bfQ133333Vi0aFGJ7YYbbojDDz+86Jw+ffrE7rvvnj/3jTfeyEn+008/PT744IN8//7rX/86mjdv/pW/HwAAAABsCepuaZ2Cd9xxR5mdgsOHD4+RI0fGlClTYuedd477778/unbtGi+99FKeJQMAAEROoF9wwQWxdu3a9Z6z00475Xvuzz//PL773e9+6c9KCf2hQ4cWvX722Wfj9ttvj3r16uWk+/e///08u33evHkxbty4mDFjxpf+LAAAAADY0tTekjoFt91227j44otLHVuxYkXeP2rUqGjXrl3Url07evXqFT169CjRuQcAADXdWWedlcu6p3vo9Zk7d24+PnDgwC/9OWkQ7Jo1a6JLly5F+w466KC45ZZbYtWqVfGPf/wjnnrqqTxA9qqrroq+fftGs2bNvvTnAQAAAMCWpnZV6BScOnVqns3eqVOnEvt79uwZ48eP34ytBAAAkuuuuy6XhS8uDY59++2388z53r1751nu9evXjwcffDD69etXaW0FAAAAgGpfRn59pk+fHh06dCi1v3379jFr1qxYvXp1LlW5rpUrV+at0JIlSzZ5WwEAoLr75z//GS+++GKMHTu2xP4ddtghl4sv7le/+lWcc8458dlnn8Vpp52WZ8SnZPw111wT3/ve9zZzywEAAACghiXbly1bFi1atCi1v2XLllFQUJDXem/evHmp40OGDInLL798M7USAABqhhtuuCF+8Ytf5FnrGzJ//vx46KGH8uDZE044IS8JNWfOnHjsscfyklBvvPFGtG3bdrO1GwAAAACqZRn5DWncuHEsWrSo1P60r1atWtGoUaMy3zdgwIBYvHhx0ZbWpgQAAL68dA9+77335mWgvkhaq/3cc8/N9+yTJ0+OoUOH5nv3H/7wh3l997QPAAAAAKqqKjGzPZWQHz16dKn9M2fOzKXkyyohn6SZNl802wYAACgpVY9KCfKyDB8+PLp37x5t2rTZ4DXee++9ePjhh+PNN9+MtWvX5n3Fr1mnTp2oXbtKjP0FAAAAgDJVid6tww47LCfW0/rsxaX1IFNHHwAAUHG6deuWy8Sv6/PPP4+bb745zjvvvI2e1b711lvnSlVdunTJladWrVoVkyZNir///e95H7Dla926dSxYsKDU/mHDhsWuu+4aTZo0iUMPPTRee+21SmkfAAAAVJYqkWxPpSYHDRoUvXv3jnnz5sWaNWtizJgxMXbs2Ojfv39lNw+ALVTqAH7nnXcquxkAVU5KnKUE+brS/XeqOvUf//EfXzirfcKECSVKzY8aNSrefffd2G677eL888+P+++/P7bffvtN0n6gYixfvjyuv/76+Oijj8qscjFy5MiYMmVKXrbt7LPPjq5du8YHH3xQKW0FAACAylAlysgnKameSk0ecsgheUT9AQccEBMnTswj7AGguNThe+211+YlSM4444zKbg5ApZaD35Df/va3Ze6/7777ytzfq1evvH2Rf//733HrrbdGw4YNi/alsvMPPvjgF74X2DLcdtttccEFFxQtA1HcihUr4uKLL45nn3022rVrl/el/zY899xzMXTo0Lj66qsrocUAwIakfvS0xFOrVq1KTVT44x//mAfX7bPPPnHLLbfEXnvtVWntBICqpvaW2im4btBP0oP+7NmzY9myZfH4449H586dK6V9AJRfStykh7ZmzZrFbrvtlmc1ri8JlEqQnnbaabHjjjvm2ZV77713XjpkXX/4wx9ip512irp16+YtdfamUqbf/OY347rrrstVUdJ+ADavgw46KI466qjKbgbwFaTKFJ9++mlOrK9r6tSpsfPOO0enTp1K7O/Zs2eMHz9+vddcuXJlLFmypMQGAGxaKtUAQA1MtgNQvaRZ5ldeeWWeIZUe3p588smcRC9rplRhNZOUYE9J93R+eijs27dvfl+he++9Ny8p8vzzz+dzfvKTn8Q222wTb7/9dtxzzz25TPHJJ5+8Gb8lAEDNMH369LykxLrat28fs2bNitWrV5f5viFDhuSBl4VbGjQJAGw6qR9m2223zRVp1lepJi33lCYv1K5dO1eq6dGjR65UAwBsHMl2ADapmTNnxuDBg2Py5Ml5pmOyww47xOWXX56XBynLAw88EP369YsWLVrkh73DDz88zjvvvBIzpVLZ0uOOOy5fq1GjRrlcfOH1Ullks9oBADaNVG0u3aetq2XLlrlyUZpBV5YBAwbkQZKF29y5czdDawGg5toUlWoAgJIk2wHYpO6888446aST8lq9G6tx48al9n322Wc5qV4oJe5TUj510qYSpKn02fHHHx8vvfRSnlF14oknVth3AACg5L3aokWLSu1P+2rVqlXinq24+vXrR9OmTUtsAEDVqlSTWBoGAP6PKX8AbFJpBvq5556by5LddNNNMXv27Pj6178eV1xxRXz/+9//wvenWU9pRPXo0aPjqaeeKtqfEvhz5syJ7373u/H555/n5PqFF16YZ7tfeuml6501D1BRFk28qbKbQAVrftSvKrsJUCWkjvl0b1ZWRaPUQV+vXr1KaRcAULGVapo3b77epWFSxUIAwMx2ADaxDz/8MG688caYMGFC3H333TF//vy8JntaAyzNQl+flIhPa3mmddhPO+20OOWUU0o9BKZSpGmN9pR0v+qqq+J///d/8+u0xlhaXyytOZbKzP/nf/5nrFmzZjN8WwCA6u+www7LifU06624cePGRffu3SutXQDApq9Uk1gaBgD+j2Q7AJvUVlttFZ07d46xY8fG7rvvnl+n2edp3bA77rhjve979NFH8wNbKlv21ltvxZtvvpnftyFpVHWa1X7//ffHsGHD8jVeeOGF+J//+Z88qx4AgK8udb4PGjQoevfuHfPmzcuDGseMGZPv99KgSgCgalSqWXfg3MZWqrE0DAD8H8l2ADapjh075hnm60oJ+FRS/ouk0dTpIe+uu+7KyfOyRl0nL7/8cr7eT37yk3jwwQfj17/+dS5Xv+OOO8ZvfvObXIoeAICKkZLqxx9/fBxyyCG5GlEaRDlx4sRo3bp1ZTcNANgIKtUAQMWQbAdgk0rl4keMGBErVqwosf/FF1/Mo6iTtWvXfuF13nvvvTyqOo2e3tCs9pScT2uL1a79fyEurd9e/DUAABsv3Vu1atWq1P4LLrggD3ZMa74+/vjjeTAlAFA1qFQDABVD5gGATapnz56xyy675BLwqTN21apVMXr06PwA169fv3jggQfyDKjUSVuoT58+8V//9V+xdOnSnIhPa7v/+Mc/josuuigaNmxY6jNeeeWV+Pe/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue\n", + "\n", + " ratio_df = mall_df[\"์„ฑ๋ถ„ ํ‘œ๊ธฐ ๊ฐ€๋…์„ฑ\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"์„ฑ๋ถ„ ํ‘œ๊ธฐ ๊ฐ€๋…์„ฑ\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๋ณด๊ด€ ์ •๋ณด\n", + "- ๋ณด๊ด€ ์ •๋ณด ์ œ๊ณต ํ˜•ํƒœ ํŒŒ์•…" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB9sAAAH/CAYAAAD38r1XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAlwxJREFUeJzs3QeYVdXVOO5NE1C6BewoBgE1sSYavxA1xIiNKCZgLKCJUURFJRKJLWoiRom9N0LsCkY0JtgQ7DX62VBCFEFQIypVAYX5P2v//jPfVGCUYWbuvO/zHOGec+65+w7gOvusvdduVFRUVJQAAAAAAAAAgJXWeOVPBQAAAAAAAACCZDsAAAAAAAAAVJNkOwAAAAAAAABUk2Q7AAAAAAAAAFSTZDsAAAAAAAAAVJNkOwAAAAAAAABUk2Q7AAAAAAAAAFSTZDsAAAAAAAAAVJNkOwAAAAAAAABUk2Q7wAo88sgjqVGjRmnixIm13RQACti0adMaVLzZbbfd0sCBA2u7GQAAAFAQff8pU6bkvnbr1q3ThhtumD788MO0Ov3lL3/J3w0amqa13QAAAAAAAADg6+vbt29asmRJuvzyy9NXX32VmjdvXttNggbBzHZgpcWotBidBgAAALAiniMA0JBFNbeYab46fPbZZ+n1119P55xzTv7cX/3qV6l9+/ar5bOhoZNsBwAAAAAAgHpq3rx5+deOHTvWdlOgwZFsBwAAAAAAgHqqqKiotpsADZZkO9SSxYsXpxEjRqQePXqkFi1apA022CANHjw4l3sJUWZtnXXWyWurnH/++WnLLbdMa665Zj4/1lxZtmxZPu+vf/1r2m677VLLli3TZpttli666KIKn3XnnXemXr16pXbt2uXPivPvuOOOSsu7/f3vf0/XXXdd6tq1a2rSpEk68cQTc6mbOBaOOOKI/PvYpk2bVvLeqVOnpkMPPTSPnIvP2HbbbdOoUaNKjs+YMSNf78ILL6z05/Hqq6/maz733HMr/TMq/XP65JNP0pFHHpnWXXfdfJ1XXnklHXLIIWnjjTdOS5curfQzo4377rtvyes475JLLklbbbVV/ryNNtooDRkyJM2ePftr/UynTJmSGjdunK699tpKP//ee+/NbX3xxRcrPQ5Aw/XSSy+lvfbaK7Vt2zatvfbaufzbBx98UCZmXXnllTmWxT1AxL+DDz44vf3222WuE6XjDjrooBzLjjnmmLT++uun1q1bp1133TU99NBD+ZzPP/88nXXWWalLly45pm2//fbpwQcfrNCmuXPnplNPPTVtvvnmed23zp07p9NOOy198cUXJef8/ve/z2368ssv87GIw8X3BaNHj/7apfXis+Laxe655570gx/8IHXo0CG1adMm7bDDDvl+Kb4LABSqQnuOAAB1UfQrhw8fnvuha6yxRo63EcuefvrpktgW/fMTTjghbbHFFiXPkfv375+eeeaZkpgc50Y/eNKkSSVxsHS/dmX6/iHi9zXXXJP76sX9/8MOOyy9//77JedEWyOmh913371M3I3P3HHHHdN7772X13SP2B7H5syZU6YdP/3pT3MfO+4ddtlll3T//fdXaMeNN96Ydtppp9wPjxL18Wzhqquuyvce5d111125rx7X22STTdIf//jHtGjRolXyZwR1TdPabgA01ID9k5/8JAexY489Nnda//Of/6RLL700PfnkkyVBOUajRQCcOHFiOumkk9K3vvWtnKCNQB7BMYLryJEjc0L4lFNOSY8++mgaOnRofgAeHe5w22235SR0PICPZHg8/B47dmx+HUG1X79+Zdp200035UB6/PHHp5133jmtt956JQ/pDzjggLx/jz32yOfGsfDUU0+lvffeO994xI1I3BiMHz8+/fKXv0wzZ85Mp59+en7Y/qMf/Si3J9pa3i233JIfAHzve99b6Z9RBOrSP6fp06enM888Mwf6SPpHW+PzouPfp0+fMp83efLk9L//+785EVB8jfhZ/O1vf8s3T9HmTz/9NN8QRTKjtJX9mcaDhj333DMn248++ugK3/n222/P3zludgCg2IQJE9Kf//znPGhswIABOf5dcMEFOc7H4LSIfxGbI15HzIoE+EcffZTjVcSUBx54IPXs2bPkehHDv/vd76amTZum3/3ud/n9cW506MeMGZMfvsegubjXiBge9wL77bdfev7553OSPPz3v//ND80//PDDHF8jxkVbYpDaCy+8kON+DDArFg8Z4poRZ1u1apWT45FQj+8S68d9E5FkiO8RP4Ojjjoq73viiSfydSN2x88KAApNoT1HAIC6Gm8jZr3xxhvpuOOOy33iSGpHsrt40FnEt0g4R8yNc2JAejyXjvgZyef58+fna8Rz5ssuuyz3p//whz/k93br1m2l+/4xUD4S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BgwoeX3LLbcUffe73y1q0aJFUfv27XOMfPvtt8u8J86P91XmrLPOKtp0001X+tjnn39edO655xZ169Ytx+WI+QMHDix67bXXKrzv6aefLtp3332LWrdunbe999676Pnnn1/u95k3b17R4MGDizp16pSvH/ccF198cb4fiHPj2mH69OlFw4YNK/r2t7+dr7322mvn4xGLAaCQFdpzBACoi2bNmpX7qtHXjGfEP/rRj3K/d+TIkUWbb7550bJly4ruuuuuov32269oww03zH3yeBZ+4oknFv33v/8tc62IqX379i1q1apVUYcOHYpuvPHGavf9i/v/u+yyS47B0f/v3bt30QMPPFDmnKquu7y+f7E333yz6OCDD873FvF9ttlmm6Lzzz+/aMGCBSXnvPHGG0XHHXdcUffu3XM7ou8e7YhYv7LP6ld03wD1VaP4T20n/AFWhxidF+XcYzZcbbj//vvzzPkYGdilS5daaQMA1KTf//73edT+tGnTarspAAAAUC1RHn7bbbfNpdVLi4ptMds9Kq9FtReA0pSRBwparGezZMmS9Mgjj6RXXnml0hLyNSnK7t166625nE+Uqo9SexLtAAAAAAB1SyxRdsABB+SlzrbZZpvUsmXL9M477+RB5bE2eixdBlCeZDtQ0F566aW8Js7666+fZ7THTdLqFOvWnnfeeWnevHl53dpYvwYAAAAAgLplxIgR6fvf/36evR6Ttj7//PO8rvlPfvKTdMYZZ+RnzADlKSMPAAAAAAAAANXUuLpvAAD4uo466qi09dZbV9h/zTXXpM033zy1bt069ezZM7322mu10r5C9uGHH6aLL764tpsBAAAAAFAwJNsBgNW27tX48eMr7I/lFaI014QJE9LcuXPTsccem3r37p0++uijWmlnIZo8eXI68MAD02effVbbTQEAAAAAKBiS7QBAjZs1a1Y6/fTT05///Ocy+xctWpROPfXUNHr06NS5c+fUuHHj1L9//9S3b980cuTIVJ889dRTqV+/fqljx46pTZs2aZdddkkTJ06scN5VV12VevTokc+J2fxnn312Wrp06XKv/emnn6Zzzjknbbfddqldu3Zps802y2uFLVmypOScDz74IB1wwAH5ePwcmzVrlrbddtvcnmjXm2++mU4++eQa+e4AAAAAAA1R09puQF20bNmynBSIUraNGjWq7eYAQLUVFRWl+fPnpw022CAnXmu7LQMGDEgXXnhhWmuttcoci2T0Jptskrp161ZmfySHBw4cmN9TmcWLF+etdOyOhPTaa69da7H7uOOOS7/+9a/TJZdcktZYY430z3/+M88mf+SRR9IWW2yRz7n22mvTzTffnAcXdO3aNb311lu5tH78WZ155plVXjtm/n/88cfppptuygn66dOn5woAn3zySTr//PPzOYceemhOrt9www3pnXfeSfvtt1865JBD0tFHH51+85vfpH333Tf/XZg3b95q+5kAUH/jd12ijw5AfdfQYrzYDUBDit+NiuJMynj//ffTxhtvXNvNAIBvbMaMGWmjjTaq1TbEDPV33303XXnllTm5Hknp119/PR+LNcSfeeaZdNddd5V5T5SQX3/99XNCPWZol/f73/8+zwgHgEJUF+J3XaKPDkChaCgxXuwGoCHFbzPbKxEj7op/eFHiFQDqm5i9HB3b4phWW1555ZV0yy235IR6ZRYsWJDat29fYX+HDh3yyMGFCxfmsujlDR8+vExJ9FjrPWbI17XYfcwxx6Rdd901HXbYYSWzz7/97W+nYcOGlZwTZfRD8Qz1lfXggw+ms846Kz377LP5dZ8+fdI222yTZ8hPmTIlHXzwwen+++/PgxzWW2+9dMopp6zS7wZA4cbvukYfHYD6rqHFeLEbgIYUvyXbK1Fc2iZuBNwMAFCf1Wa5ti+++CKXgo8S6C1btqz0nFatWqU5c+ZU2B/7ou3ly84Xa968ed7Kqyuxe/bs2blc/Kuvvpquv/76ku9xwQUXpD322CN9+OGHucz73XffnUsQXXPNNWnNNddc6evPnDkzDziIxHrx97311lvT8ccfn7baaqtc2ig+d5111kl///vfc7n6hvJQB6AQKLdalj46AIWiocR4sXv1iecLt99+ezrppJNquykADTZ+F/4CMVDNm5MoaQzAN/fiiy/mGda77757np0eW6wbPnny5Pz7gw46KK9bPnXq1Arvjfd16dKl0hLyddmWW26ZHyR07NgxnX766Xlme4sWLUqOx9rtkSQfN25cnvH/5JNP5rXYK/sZVOWJJ55I3//+99OgQYPS4YcfXrI/Euxjx47NJfhffvnltOeee6YRI0bksv0x8OFnP/tZXtM+1nV/9NFHV/l3BwDqvxigFwMlAYC6L56vHHjggemzzz6r7aYA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SCNHjkz77rtvPieS6jFYftddd02zZ89OO+20Uxo/fnxab731arv5AFAnmdkOANSY/fbbL917771p0aJF6auvvkqPPfZYOuqoo/KI+fD444+nQw45JL3yyiupqKgod+RPPvnk9MYbb5SUmgcAAABWjZjF/vTTT6dPPvkkffzxx2nSpEklifZiQ4cOTdOmTUsLFizI/fhIyAMAlZNsBwBqzJAhQ9JNN92UNtpoozwK/rTTTktXXXVV+uUvf5mPb7/99mmbbbbJa7S3bt06de/ePc2ZMyd3/GMNdwAAAAAAqKuUkQcAakyvXr3yVpVWrVqlU089NW8AAAAAAFCfmNkOAAAAAAAAANUk2Q4AAAAAAAAA1STZDgAAAAAAAADVJNkOAAAAAAAAANUk2Q4AAAAAAAAA1STZDgAAAAAAAADVJNkOAAAAAAAAANUk2Q4AAAAAAAAA1STZDgAAAAAAAADVJNkOAAAAAAAAANUk2Q4AAAAAAAAA1STZDgAAAAAAAADVJNkOAAB10Icffpguvvji2m4GAAAAAFAFyXYAAKhjJk+enA488MD02Wef1XZTAAAAAIAqSLYDANAgPfXUU6lfv36pY8eOqU2bNmmXXXZJEydOrPL8YcOGpZEjR6709e+555601VZbpdatW6cddtghTZo0qczxDz74IB1wwAGpXbt2qXHjxqlZs2Zp2223ze2Jdr355pvp5JNP/kbfEQAAAACoOZLtAAA0SEOGDEm9e/dO77zzTvrkk0/SKaeckvr27ZumTJlS5rxly5alF198Md12220rfe1//vOf6dRTT0133HFHmjdvXvrTn/6UDj744JxALzZw4MDUvXv39PHHH6c33ngjrbPOOumXv/xl+uijj1LPnj3TSSedlBPxAAAAAEDd1LS2GwAAALUhZrG3atWq5HWUbX/ooYfSgw8+mLp27Zr3zZ07N2200Ubpyy+/zNvKGjp0aLrsssvSNttsk1/36tUrJ/PPOuusdPfdd+d9Tz/9dLr22mvzjPZIuv/4xz9OTZo0STNnzkxjx45Nb7311ir/zgAAAADAqmNmOwAADVLpRHuxL774Iq211lolr9u2bZvmz5+fFi1alA477LCVum4kyWN2eiTPS4vS8A888ED66quv8uudd945XXnllWnJkiXp1VdfTU888USeaX/++eenwYMH588GAAAAAOouM9sBAGjwZs+enW6++eb00ksvpauuuuobXWvy5MmpS5cueZZ6aRtssEH+9b333svHR48enY4//vi08cYb52Mxy7158+Z5rXez2gEAAACg7pNsBwCgwdpyyy3TBx98kBYuXJhatGiR11aPX7+JBQsWpPbt21d6LPbHTPkQCfYoF19aJN+PO+64PMP+yCOPTBMmTMjJ+D//+c/pRz/60TdqFwAAAACwakm2AwDQYL399tv516VLl+YZ6ZHsfv3119M111zzjcrTz5kzp9Jjsb9169aVHps1a1a69957czsOOuig1Llz5zR9+vT06KOPpr59+6Y33ngjbbjhhl+7XQAAAADAqmXNdgAAGrwo+b711lvnNdTvuOOOb3Strl27pnfeeSctW7aszP6ZM2fmfZtuumml74u12k844YTUqFGj9Mgjj6SRI0fm9eP333//vL577AMAAAAA6g7JdgAAKJUQb9u2bbXeUz6pvtVWW+XZ64899liZ/VEyfp999klNm1YsLhWl7O+77740ePDgVFRUlPdF0r30YIDGjd2613Uffvhhuvjii2u7GQAAAACsJp7YAQDQIO233365bPuiRYvSV199lZPjRx11VDrzzDOrdZ1tttkmjRgxosy+eB2J87feeisnzx988MF0wQUXpHPOOWe5s9rXXHPNXIa+V69eafjw4WnJkiXpoYceSs8++2zeR90V5f8PPPDA9Nlnn9V2UwAAAABYTSTbAQBokIYMGZJuuummtNFGG6X11lsvnXbaaemqq65Kv/zlL6t1nTZt2uRy76X169cvX69Pnz55lvvpp5+e7rzzztSjR49KZ7Xff//9adCgQSX7Ro8end5///3UqVOndPLJJ6e77rorrb/++qmhe+qpp/LPtmPHjvnnvssuu6SJEydWqDQQgxpiffuoUrDvvvum6dOnr9T177nnnpLKBDvssEOaNGlShT+rAw44ILVr1y5XGmjWrFnadtttc3uiXW+++Wb+8wIAAACgYahYwxIAABqAmClendnif/nLXyrd/8wzz1S6/7DDDsvbirz33ns5yd+yZcuSfZG8jcQvFQdIHHfccXmQxBprrJEHKfTt2zf/GXTt2jWfEwMbXnvttfTyyy+n9u3bpyuvvDLtueee6ZVXXkktWrSo8tr//Oc/06mnnprL/W+99dbp0UcfTQcffHB65JFHSgZJDBw4MCfhY/DD1KlT0x577JEHZxx//PG5Xeuuu25OxAMAAADQMEi2AwBALdp5551ruwn1RsxijzL7xaJse5TZjzL9kWyfOXNmuuKKK/JM9uKk94knnpiXCLjxxhtzaf+qDB06NF122WV5WYAQAzFOOeWUdNZZZ6W7774773v66afTtddem2e0d+/ePf34xz9OTZo0yZ8bSfpYNgAAAACAhkMZeQAAoF4onWgv9sUXX5SU8Y+Z7jHbvPzs8ijxPm7cuCqvG0nyjz76KCfPy7/vgQceSF999VXJwIiYKb9kyZL06quvpieeeCL17t07nX/++TmRH2XrAQAAAGg4JNsBAIB6Z/bs2eniiy9OL730Uk6Kh8mTJ5eUky+tS5cu+VhV4licE7PUS9tggw1KSv2H0aNHp3feeSdtvPHGacCAAXmWe/PmzXPJ/yhxDw1NDFI58sgj04YbbpgHuey666556YXSrrnmmrT55pun1q1bp549e+ZlHgAAAKBQ1Ktku448AAA0bFtuuWVq06ZNXtc+1mc/5phjStZiX7BgQV6nvbwOHTqk+fPnV3nNqt4XYn/xeyP5HuXio18Sa8LHWvAjRozI67XHDPuf/exnae21107bbrttXvMdCt0+++yT/31FdYiPP/44DRo0KB1wwAHpjTfeyMevu+66NGrUqDRhwoQ0d+7cdOyxx+ZqEPFvCAAAAApBvUq268gDAEDD9vbbb6d58+blUu7PPfdcTn4Xr8UeZebnzJlT4T2xLwbjVqWq963ovbNmzUr33ntvOv7449Phhx+eE+2xXvw555yT+vbtm9dyh0IVVR6mTp2aRo4cmf+NNGvWLB166KF5KYcnn3wyLVq0KJ166qm5IkTnzp1T48aNU//+/fO/jXgPAAAAFIJ6k2zXkQcAAIpFyfett946r6F+xx135H1RQj76DOVNmTIldevWrcprxfuiv7Fs2bIy+yNZHvs23XTTSt8Xa7WfcMIJqVGjRrniVvQ7Yv34/fffP6/vXr4KFxSSGAgf/fBp06aV7ItB76+++mraaaed0sSJE9Mmm2xS4d9eLPswbty4WmgxAAAANOBku448AABQXiTE27Ztm3+/9957p4ceeijPfC8tZr/36dOn5HX5pPpWW22VB/Q+9thjFd4X1bWaNm1a4XM/+OCDdN999+VZ9UVFRXlfJN1LDwaIAcBQqGJpt/POOy8v7xYDTW655Zb87+Xss89O22+/fZo8eXIeyFJely5d8qCYL7/8ssprL168OP87Lr0BAABAXVRvnv7oyAMAQMO233775bLtMQj3q6++ysnxo446Kp155pn5+GabbZYOO+ywNHDgwPTpp5/mUvMXXXRRXobqV7/6Vcl1ttlmm7zWemnxOhLncW4kzx988MF0wQUX5JLwy5vVvuaaa+Yy9L169UrDhw/PnxkJ/2effTbvg0IWg9tj8Hss53bXXXflwfGvv/56+vzzz9OCBQtS+/btKx1IH//GFi5cWOV1499jDKIp3jbeeOMa/iYAAADw9VScolHHO/KPP/547shHEr26HflI2FfVkY+kPQAAUHcNGTIkXXbZZTlxHrPTo6rVVVddlWe0F7v00kvTWWedlUvMRx9h9913Tw8//HBq0aJFyTlt2rTJ5d7L9zUiUR4z4GO2fPfu3dOdd96ZevToUems9vvvvz+98cYbJftiOatBgwalTp06pQ022CAnHtdff/0a+1lAbYtBJTHY5fLLL89LJ4QY5HL00Ufn5dz23HPPNGfOnArvi31RBaL8v8HSYuDKySefXPI6BsRLuAMAAFAX1Ztku448AEDDNWf85bXdhILVbq/jU30RM8VXNFu8WbNmuSJWbFV55plnKt0fs+JjW5H33nsvJ/lbtmxZsq9jx47pnnvuWeF7oVBERYkLL7ywpH9ePNj9xhtvzAPh+/fvn6vMlTdlypQ8eD7+rValefPmeQMAAIC6rnEhdOQjER+//yYd+ZjdUnoDAACozM4775z22muv2m4G1LrGjSs+Unj//fdzH/uggw7K/fHy/fSxY8fmChIAAABQCOpNsj3oyAMAAEDtiypzJ554YnrwwQfzEgyxTZgwIR144IF5sHxUlzvjjDPSgAED8tIMS5cuTbfddlsaM2ZMGjZsWG03HwAAABpWGfnijnzr1q3zuovhySefTMcee2yFjnysjxhrJcYai9GRf/HFF2u7+QAAAFAwjjjiiNS2bdt09tlnp1/84hd5cHyPHj3SyJEj07777pvPiaR6kyZN0q677ppmz56ddtpppzR+/Pi03nrr1XbzAQAAoGEl23XkAQAAoO6IWeyxLc/QoUPzBgAAAIWo3iTbg448AAAAAAAAAHVBvVqzHQCoX5566qnUr1+/1LFjx9SmTZu0yy67pIkTJ5Y5Z9myZemc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a6/UqVOntO6666Y+ffqkt99+Ox9/7733UsuWLVO7du0qbLNmzart5gMAAAAAQJUk2wGAGjN37tx02WWXpWHDhqVp06al6dOnp1122SX16tUrzZ8/PyfjmzRpkubMmVNh22CDDWq7+QAAAAAAUCXJdgCgxrRt2zZNmjQp7bHHHqlFixZ5Fvupp56a97/wwgu13TwAAAAAAPjamn79twIALF+jRo0q7Pvyyy/Tp59+mtq0afO1r7t48eK8FZs3b97XvhYAAAAAAHwdZrYDAKtNlI0fMmRI6t69e9pxxx3zvmXLlqUzzjgjdevWLa299trpe9/7Xho3btxyrzNixIg8O75423jjjVfTNwAAAAAAgP9Hsh0AWC0+++yz1KdPnzR58uQ0duzYvC/Kyu+6666pQ4cO6YknnkizZs1Kp512WjriiCPS+PHjq7zW8OHD83rwxduMGTNW4zcBAAAAAADJdgBgNXj++efTTjvtlHbYYYf06KOPpnbt2uX9HTt2TA8//HA66aST0rrrrpuaN2+e9t9//3T66aenq6++usrrxXlRhr70BgAAAAAAq5NkOwBQo+6///500EEHpdGjR6ezzjorNW684tuPb33rW3mWOwAAAAAA1FVNa7sBAEDh+uSTT9KgQYPSQw89lHr06LHS73vkkUfStttuW6NtAwAAAACAb8LMdgCgxtx9992pb9++VSba33vvvbT33nunp556Ki1btizNmzcvXXDBBen222/Pa7cDAAAAAEBdJdkOANSYqVOnpmuvvTa1atWqwvbb3/42bbDBBmmfffZJw4YNy+u4b7rppumFF15IzzzzTOrcuXNtNx8AAAAAAKqkjDwAUGNGjhyZt+UZPHhw3gAAAAAAoD4xsx0AAAAAAAAAqkmyHQAAAAAAAACqSbIdAAAAAAAAAKpJsh0AAAAAAAAAqkmyHQAAAPha7rjjjrTddtultm3bpi222CKdfPLJqaioKB9btmxZOuecc9KGG26Yj++7775p+vTptd1kAAAAaLjJdh15AAAAqH0XXXRR+uMf/5iuvvrqNHfu3PT444+n1q1b5755OP3009MLL7yQXn755TR79uzUq1evtOeee6ZFixbVdtMBAACg4SXbdeQBAACg9k2ZMiWdd9556ZFHHkk777xz3rfBBhuks88+OzVp0iTNnDkzXXHFFenmm29O6623XmrWrFk68cQT05ZbbpluvPHG2m4+AAAANKxku448AAAA1A033HBDOuSQQ1LHjh0rPX7//fenPfbYI7Vr167M/n79+qVx48atplYCAABAzao3yXYdeQAAAKgbnn766bTrrrum0aNHpx133DGts846aZdddkkPP/xwPj558uTUtWvXCu/r0qVLPrY8ixcvTvPmzSuzAQAAQF1Ub5LtOvIAAABQN/z3v/9Nl112WR74HhXmZs2alYYNG5b69u2bXnrppbRgwYLUvn37Cu/r0KFDmj9//nKvPWLEiNS2bduSbeONN67BbwIAAABfX9NUzzrynTp1yh35SKI/8MADuSP/2GOP5Y58HPu6HfkoRw8AAACs2BprrJF69OiRrrvuupJ9BxxwQHr22WfT9ddfn1q1apXmzJlT4X2xr3Xr1su99vDhw9PJJ59c8joGxEu4AwAAUBc1rm8d+TFjxqTu3bvn19GRHzRo0CrpyM+dO7dkmzFjRg1+EwAAAKjfttxyy9S5c+cK+6PfPm3atFx5burUqRWOT5kyJXXr1m25127evHlq06ZNmQ0AAAAKKtn+0Ucfpf/93/9Nzz33XPr3v/+dvvrqq1STdOQBYPVY3TEeAKh/8TuqzN14441p0aJFZfa/+OKLuX++9957p4ceeqjCMm1jx45Nffr0qdG2AUAh0UcHgAJKtkcwHzJkSNpss83SBhtskLbffvu8bnoks2MdtV69eqVbbrklLV26dJU3VEceAGpObcZ4AKD+xe9+/frlz42KczEAfsmSJfmzbrvttpI2HXbYYWngwIHp008/zccvuuii9NZbb6Vf/epXq7w9AFBI9NEBoMCS7V988UU66aSTclCPEuuxdlqsk/7qq6/mmeMvvPBC+utf/5p23HHHdM4556StttoqPfroo6u0oTryALDq1YUYDwDUv/jdpEmTdN999+WH/t/73vdS+/bt00033ZQeeeSR1KVLl3zOpZdemo9vvfXWaZ111kmTJk1KDz/8cGrRosUqbQsAFIq6EOMBgOppuqITIoD/4he/SD/60Y/S22+/nUfSVSZuAGL2+fnnn5/GjRuXjjvuuLTbbrulq6++Oq3Kjvxpp52WO/ILFizIv5bvyJ911lm5Ix/Hd999dx15AKjjMR4AqJ/xe80110wXX3xx3irTrFmzdN555+UNAKg/MR4AWIUz29999900evTo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498BAAAAAABKa1rmFQDAKnb//fenwYMHp9tvvz3tuuuuZY5FCflbbrmlwnumTJmSS8k3a9as0ms2b948bwAAAAAAUFvMbAcAaswnn3ySBg0alMaPH18h0R522223nFiP9dlLizLzUXIeAAAAAAAKLtn+1VdfpQcffHDVtgYAqHWrMsbffffdqW/fvqlHjx6VHo8y8WeccUYaMGBAmjlzZlq6dGm67bbb0pgxY9KwYcNWSRsAoCHQRweAwiTGA0CBJts///zzdNBBB63a1gAAtW5VxviYsX7ttdfmtdnLb7/97W/zOZFUP/DAA/PM97Zt26brr78+z4Rfb731VkkbAKAh0EcHgMIkxgNAASTbv/jiizwz7e9//3uecRbWWGON1LRp1Uu+T548edW1EgCoETUd40eOHJkWLVqUFixYUGH705/+VHLe0KFD07Rp0/L+xx57rMqZ8ACAPjoAFCoxHgDqn6qj9P9v3rx56bvf/W5avHhxDvZdu3bND8EjyDdr1iyfs2TJkrTXXnuloqKitOGGG6Zbbrkl9e7dO7377rupUaNGq+N7AADVJMYDQP0jfgNAYRLjAaBAZ7ZfeeWVOYBHwH7vvfdSkyZN0q233poaN26cA32IQP7OO++kQw45JD3//PN5X8uWLQV4AKjDxHgAqH/EbwAoTGI8ABRosv3hhx9OJ554Yv598+bN87qq9913X349f/781LNnz/SjH/0orbPOOulXv/pVvgkoDvIAQN0lxgNA/SN+A0BhEuMBoECT7f/5z39S586dS17vsMMO6c0338y/X3PNNdPRRx9dJrjHjUBY3joyAEDtE+MBoP4RvwGgMInxAFCgyfZYI6a0tddeO33yySf591G+JkrWHH744SVBPsrahOLXAEDdJMYDQP0jfgNAYRLjAaBAk+3l13v58ssv01dffVXhvKKiolXbMgCgRonxAFD/iN8AUJjEeACon1ZYYyZGzUUALw72//3vf/OouhD7ZsyYkY8vW7Ys7yv+VdAHgLpNjAeA+kf8BoDCJMYDQIHObO/atWt6+eWXS14/+eSTaYsttsi/nz17dv59ly5dSoJ68a/FwR4AqJvEeACof8RvAChMYjwAFGiyvXfv3umiiy4qWTfmkksuSX369MmvO3TokPctWrSoJKgvWLAgTZgwIc2ZM6em2w4AfANiPADUP+I3ABQmMR4A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vpU6deqU+vTpk6ZOnVpy3ujRo9M777yTNt544zRgwIA8y7158+bpnnvuSUOGDFlN3wgKl2Q7AAAAAAAA1AGRBI9S75deemnabbfdqjzv008/zWu2H3roofnXJ598MifZt91229SrV680f/78fN4GG2yQy8XHTPmXX3457bnnnmnEiBHpuOOOS1988UVe833ttdfO73v00UdX4zeFwmDNdgAAAAAAAKhFUeZ92LBhacKECenhhx9OW2211XLPX2ONNfIa8Mccc0z6xS9+UbI/ZsSPHz8+PfDAA6l///4V3jdr1qx07733psmTJ6eDDjoode7cOU2fPj0n2vv27Ztn1W+44YY18h2hEEm2AwAAAAAAQC1ZvHhx+slPfpJLwT///POpRYsWK3xPzEaPLZLl5fXo0SNNmzat0vfFWu0nnHBCatSoUXrkkUfSnDlz0lprrZX233//vL577Ity88DKUUYeAAAAAAAAaskf/vCHtNlmm6Xrr7++ykR7lIovLZLlBx54YLriiisqnBdruXft2rXCNT744IN03333pcGDB5dcL65TrEmTJqlxY6lDqA7/YgAAAAAAAKCW3HTTTenCCy9c7jn77rtvOvroo8vsi5LxkyZNSr/73e/SZ599lubNm5dOPvnknECPmepVzWpfc801U6tWrfLa7sOHD88l7B966KH07LPP5n3AylNGHgAAAAAAAGrBggUL8ozzysrBh5kzZ6a2bdum1q1b5wR5aeuvv3568skn09ChQ9Omm26aZ6bvt99+ec33pk3LpgDjM+6///68Jnux0aNHp0GDBqVOnTqlDTbYIN111135msDKk2wHAAAAAACA1aB8OfhIoC9btmyF77vjjjsq3R/l5++5554Vvv+9995LV111VWrZsmXJvo4dO67Ue4GqSbYDAAAAAABAAdt5551ruwlQkKzZDgAAAAAAAADVJNkOAAAAAAAAANWkjDwAAAAAAAAFYc74y2u7CaxC7fY6vrabAMtlZjsAUOuOOuqo1Lp169SuXbsy2wknnFDbTQMAAAAAgEqZ2Q4A1Lovv/wynXXWWek3v/lNbTcFAAAAAABWipntAAAAAAAAAFBNku0AAAAAAAAAUE2S7QBAnfDCCy+kvffeO6277rqpc+fOeR33Tz/9tNJzFy9enObNm1dmAwAAAACA1UmyHQCodVtttVVq3LhxXrd91qxZ6cknn0zz589P++67byoqKqpw/ogRI1Lbtm1Lto033rhW2g0AAAAAQMPVtLYbAABwyimnlHm90UYbpdGjR+dfX3nllbTddtuVOT58+PB08sknl7yOme0S7gAAAAAArE5mtgMAdVLz5s3TJptskme6V3asTZs2ZTYAAAAAAFidJNsBgDrpgw8+SG+99VbaZpttarspAAAAAABQgWQ7AFDrfvOb36SLLrooffzxx2nZsmXppZdeyuu1Dxo0KM9uBwAAAACAukayHQCodQMGDEhvvPFG2n777VPr1q3ToYcemo488sh04YUX1nbTAAAAAACgUk0r3w0AsPpEqfgbb7yxtpsBAAAAAAArzcx2AAAAAAAAAKgmyXYAAAAAAAAAqCbJdgAAAAAAAACoJsl2AAAAAAAAAKgmyXYAAAAAAAAAqCbJdgAAAAAAAACoJsl2AAAAAAAAAKgmyXYAAAAAAAAAqCbJdgAAAAAAAACoJsl2AAAAAAAAAKgmyXYAAAAAAAAAqCbJdgAAAAAAAACoJsl2AAAAAAAAAKgmyXYAAAAAAAAAqCbJdgAAABqM8ePHp8cee6y2mwEAAAAUAMl2AAAACt6XX36Z7rzzznTwwQenjTbaqLabAwAAABQAyXYAAABWqxkzZqQ+ffqktm3bpg022CCdffbZadmyZSuVMD/33HNTly5dUps2bVL37t3TFVdcUeacf/zjH2nrrbdOzZs3T02aNMmfse2226ZNN900DRs2LH/ut771rRr8dgAAAEBDIdkOAADAarNw4cLUq1evtPfee6dPPvkkvfTSS+nJJ5/MCfcVOfXUU9Pjjz+ey8DPnTs3jRo1Kl1wwQXp+uuvz8fffffddPjhh6cbb7wxff755+niiy9O8+bNy++ZOnVq+uqrr9IZZ5yxGr4lAAAA0BBItgMAALDaxEz07bbbLh199NGpadOmaf3110+33nprToxH8n157r777pxc32STTVKjRo3SzjvvnE466aQ0YcKEfPxf//pXntX+ve99L89qP/bYY/OvjRs3TldddVXaa6+98qx4AAAAgFVBsh0AAIDV5m9/+1vq379/mX3rrbdeTpw/+OCDy33vuuuum15//fWS10VFRXnWeiTXw/bbb59effXVPFM+ZrFffvnleRZ9JNsvvfTSdPrpp9fQtwIAAAAaoqa13QAAAAAajsmTJ6euXbtW2B8zzuPY8lxyySXpwAMPTC+//HL6wQ9+kMvIx/rrxx9/fD6+2Wabpb/+9a/puOOOS7NmzUo//OEP0+jRo9PVV1+devfunY8DAAAArCqS7QDUqPHjx6fmzZun3XffvbabAgDUAQsWLEjt27evsL9Dhw5p/vz5y33vDjvskI455pi8Rvv777+fy8a3bNkyzZgxI3Xu3Dmfs+++++atWKzdHrPan3jiifTQQw+lU045Jb83ZrxHSfuYLQ8AAADwdSgjD0CN+PLLL9Odd96ZDj744LTRRhvVdnMAgDqiVatWac6cORX2x77WrVtX+b5IkH/729/O50yfPj3ddddd6Z133knbbrtt2nXXXdNnn31W6fuuueaatM8++6Rly5aln//853nN9/feey+1aNEiHXXUUav0uwEAAAANi2Q7QAMU66LOnj17pRLm5557bi7r2qZNm9S9e/c8A6y0f/zjH2nrrbfOs9ebNGmS2rZtmx96b7rppmnYsGGpT58+ubwrAECIEvJTp06tsH/KlCmpW7duVb4v7kH23HPPfH+xxhpr5H3x6/Dhw9P666+fHn300Qrv+eKLL/Ks9tNOOy3985//TD/+8Y/TT37yk5zw/9Of/pTvY2JtdwAAAICvQ7IdoAFZuHBhXuv0448/XqnzTz311PT444+nxx57LM2dOzevixqzwaJ0a3j33XfT4Ycfnm688cZcovXiiy9O8+bNy++Jh+jx8PqMM86o4W8FANQnUeI9ZqWXFoMAn3vuubTXXnuV7IuZ6OU1blyxC7tkyZL00UcfVVoOPma177fffrnKTlFRUZn3xyDByq4HQPWWDYv+IgAANFSeLAA0EFdffXV+CB0J9JV199135+T6Jptskho1apR23nnndNJJJ6UJEybk47FOasxq/973vpcfWB977LElD66vuuqq/MA8ZsUDABQ74YQT0qRJk/Igvkioz5w5M/Xv3z8NHTo0rb322vmcZ555JlfViYF9xQ477LB0yy235HuMWNs93vvmm2+mAw88MN+P9OzZs8Ks9ssuuyz97ne/y6/33nvvvGZ7fPbixYvzbPdI/Ddt2nQ1/wQA6j/LhrGqGLABAPXPHXfckV5++eXabkadIdkO0EAMGjQozz5ftGjRSr8nkvOvv/56yeuYERaz1iO5Hrbffvv06quvpieffDLPYr/88stTr169crI9SraefvrpNfJdAID6q3379rnke8xub9euXdppp53S7rvvns4888ySc1q2bJnWWmut1KxZs5J9W221VZo4cWJ+KL/lllumDh065CRPlIYfN25cHhhYflb7/vvvnzbYYIP8erPNNssPBAYPHpw6deqUPv3003wOQENdNuyFF15Ihx56aP7/Y/z/OAZXx/9jS7NsGDXFgA0AqH9iUPuVV16ZjjvuuNS5c+fabk6dIdkOQJWi5PzJJ5+ct7/97W/5Qcrmm2+ejj/++Hw8Hsr89a9/zcE1HmQ//fTTafTo0XkWfe/evfNxAIDyIjETa6jH8jOzZs3Ks8xLJ8sjkROl4cs/fI/99913X37PnDlz0v/+7/+mIUOGlKzhXlok7GM999JivfYYSPjZZ5+lMWPGpHXWWacGvyVA3V427A9/+EP+/2LMSvrkk0/yoKdIfEYSPlg2rOFa2QEbMZj/xBNPzOfHYLoYvBExtjQDNgCgZsyYMSPH0Yit8Wz+7LPPrnQ5tspExdo999wzx+/od0e1uehnF/vLX/6SK9bGAPiI3zFgvVu3bql79+7p3HPPzfmAeC//j2Q7AFXaYYcd0jHHHJNuu+22dPvtt+cg/P777+dAXizKr77yyivpv//9by4737p16zyrPR6aR6nW73znO7kkbL9+/Vb6oQ8AwDcV9zDxQACgIfg6y4bdc889eYmOmNUeD1FjuY1DDjkk3X///fm4ZcManuoO2DjyyCPze2LwRSwLEw/6DzjggJLjBmwAQM2I+BsVZuP+LQZNvvTSS7n6bCTcV+Spp57Kz/SPOOKIHPPfeuutPAAzBryHmFAX8TkGyMfnxES8qEgT58V7Y6B8LDXL/5FsB6BSkVT/9re/nZPn06dPz6Ve33nnnTwCfdddd60wWr1YlGPdZ5998ii6n//853nN9/feey+1aNEiHXXUUav9ewAAABS6r7NsWCTOy4uHrG3atMm/t2xYw1LdARvPPfdc/rsR74u/M2uuuWbu/0flmQceeCCfY8AGANSMK664Im233Xbp6KOPTk2bNk3rr79+uvXWW/PAtki+V2Xp0qUlA+GiolG8t1WrVjnxHtcLzzzzTPrRj36UunbtmqvIxX1m8X3jiBEjcjyP2fT8H8l2AKoM2FFKJsq6FZdmjV+jHGsE71hrtbI1W4pntcfIt1hDNUbFRcD+05/+lMvHxUMaAAAA6paoaBbJ04EDB+bXlg1rWKo7YCOWmjvwwAPzQ/rSYtD9uHHj8u8N2ACAmhFxOEq/lxbLuuy8887pwQcfrPJ9cSye1ce9XFVikFxUrH3zzTfzfUHkCSLmRxWbqIwUS7lRlmQ7AFll67lEB7i8JUuW5NkOMeK9slnt++23X17npaioqMz7i0evAwAAULf6grFeewyaHj9+fFpnnXVKjlk2jKpMnjw5z3grL2aqx7FgwAYA1F4crkzE4qhaG79GhZlI0Pfo0SPf38Xz/PA///M/6Q9/+ENOsEesXrBgQRo5cmQ6//zzc0wvroLE/5H1ACCXhokgGeupFYu1+2655ZZc2m3+/Pn5AUyMZosgG2XgevbsWWFW+2WXXZZ+97vf5dexXkw8fJk0aVJavHhxfhgTD2rKj3oHAACgdnz44Ye5Itkbb7yRS35H8nx5LBtGsXjw3r59+wr7O3TokJ8hFDNgAwBqLw6XF/E47vlOOOGEvHRMLCUbOYCYvR4VaIodeeSReY32Dz74IF133XVp3rx5eTb98ccfn8/fcsstc6L+mGOOyeu6N3SS7QCkli1bprXWWis1a9asZN9WW22VJk6cmGc2RPCMQB3ruMSDmCgJ16hRowoPXfbff/88Wj3EqLc77rgjDR48OHXq1Cl9+umn+RwAAABqXwy2jjKhP/vZz9LYsWMrfWBbmmXDKC3+3GN99vJiXyTUq2LABgDUXhyOZWJjYlxMkNttt93y61j2JSbRxaS7qsSs9ki0v/766+nEE0/M68NHMv6dd97J94YNnemFAA1QcUmYYttuu20uDV9e7L/vvvtWOmEf67mXFg9eYgMAAKD2RGKz/LJehx9+eDrnnHPSgAEDVuoalg2jtChdO3Xq1Ar7p0yZkrp167bcARtPPfVUftZQPGAjxICNTTbZJA/YUBEPAFYuDnfv3r1CHB44cGCV74tJdXFOTLwrLUrJT5s2rdL3zJo1K9177725PP3ZZ5+djjjiiLTjjjvmY3EvefDBB6dLLrkkNWTuggFYJaJkTMxgBwAAoG4vGxYzkaLE6Mom2i0bRgzYKC3+vKMiwtKlS8vsv+eee1KfPn0qvYYBGwCwakQcvuuuu8rsmz17dnruuefyWuxVxe+I0U888UReLra0F198sdI14IsHxEXZ+UjQi9+V8xMAAAAAgAa0bFjMhIp12qMEafnt+9//foVrWDasYatswMYPf/jDPAsuSsrGWq2x/eY3v0lt27bNZeLLM2ADAFadSH5HDB01alROqM+cOTP1798/DR06NK299tpVxu+oIhNrtcd9XRyPQXPx60knnZROP/30Cp8Ta7ZHNZpjjz02vz7ggAPSX/7yl/Taa6/lgZsx0/2AAw5IDZ27FwAAANKCMXfWdhMKVquD+tV2E4AGZGWWDYuk5pdffrnS17RsWMNW2YCNcOedd6ZTTjklde7cOf99+ulPf5pntjdq1KhaAzYiQfCjH/3IgA0AWEnt27dPjz76aE66DxkyJA+YjJhaPKhtefH7rLPOSuuuu25eUuj9999PXbp0SSNHjkw///nPK12rPT5jzTXXzK9jUGacGwn2zz77LB144IG5lHxDJ9kOFJQ54y+v7SZAtbXb6/jabgIAAMBylw2j4ViZARuhdevWOUG+MklyAzYAYNX61re+lf75z39Webyq+B1ipnrxbPXl3Q9suOGGFe4DDzvssLzxfyTbAQAAAACoMQZsAED9EpVqhg0bVtvNqBes2Q4AAAAAAAAA1VSQM9tnzJiRjjvuuDRx4sS8HsHRRx+dzjjjjNS4sbEFAFAXid0AUJjEeOo7S5UVFkt4wcoRvwGgASfbFy5cmHr16pVOPvnkNHbs2PTxxx+nww8/PJ199tl5AwDqFrEbAAqTGA+Q0rX/vqO2m8AqdPS3+qdCJ34DQANPtl9xxRVpu+22y6Ptwvrrr59uvfXWtMUWW6QTTjghrb322rXdRACgFLEbAAqTGA8A9Y/4DWCwXKE5uoYHyxVc3Ze//e1vqX//sj+09dZbL+28887pwQcfrLV2AQCVE7sBoDCJ8QBQ/4jfANDAZ7ZPnjw5de3atcL+Ll265GOVWbx4cd6KzZ07N/86b968Vd6+zxfMX+XXhJo2b17zVF/MW/hFbTcBqq1xDcSb4hhWVFSU6rraiN3icf2LGf7/Xr/+HxS+WPB5jVyXmumnhAWf+zOrKctW8s+sPsXvmorxq7qPLuYXltrom7oHKSw1dd+zPO6JCsvXvQ+rTzG+LjxfF78Li/jNNyV+U9fjd8El2xcsWJDat29fYX+HDh3S/PmVB+kRI0ZUut7MxhtvXCNtBICyfltjV47Y17Zt21SXid1QuP8PomaclH5Z202g2o4suPhdUzE+iPNAzXHfQ+3eh9WHGK+PDtQ94jd1O34XXLK9VatWac6cOXktmdJiX9wQVGb48OHp5JNPLnm9bNmy9Omnn+b1Zxo1alTjbeabi9ElcfM2Y8aM1KZNm9puDhQc/8bqnxhtFzcBG2ywQarrxO7l8++v/vFnVv/4M6tfCvnPqz7F75qK8Q0tzq8KhfxvgtXD3yG+KX+HCivG66OvHv7d8E35O8Q35e/QqovfBZdsjxI3U6dOTd27dy+zf8qUKWngwIGVvqd58+Z5K61du3Y12k5qRvwPwf8UoOb4N1a/1PXR8sXE7pXj31/948+s/vFnVr8U6p9XfYnfNRXjG2qcXxUK9d8Eq4+/Q3xT/g4VRozXR1+9/Lvhm/J3iG/K36FvHr8bpwKz7777prvuuqvMvtmzZ6fnnnsu7bXXXrXWLgCgcmI3ABQmMR4A6h/xGwCqp+CS7SeccEKaNGlSGjVqVC5XM3PmzNS/f/80dOjQXLYGAKhbxG4AKExiPADUP+I3ADTwZHv79u3To48+mkffRamanXbaKe2++//X3p3ARlV9Dxw/ZWktUCgUpJYiQssueyEYjCyyKOIKKooihCWyBzQUQbYiBIOKUMSICEVBcQOhuLAES0oBDUsIWwBBMEAJOwVKWeefc395858p08KUzv79JJOZefPem/c6vfeczju9t71MmDDB14cGD9JhiiZOnHjHcEUAigdtDJ5E7C4c7S/w8JkFHj6zwMLnFTiI8d5Bm8D94ncI94vfoeBC/PYO2g3uF79DuF/8DhWfMJvO7g4AAAAAAAAAAAAAAEL3P9sBAAAAAAAAAAAAAPA0LrYDAAAAAAAAAAAAAOAmLrbDb/lihoNbt27Z3/v27dtOr+V/DgAAAP9FLgkgkNGHAQAQeIjfABCauNgOn8rKypKkpCTzuGPHjvLrr7+ax//884/ExcVJfHy8PPLII5KQkCCJiYlSq1Yt81yXR0dHS0pKilvvt2/fPqlXr16Brw8YMEBatmwprVq1knXr1tmXb9iwQTp06FDk8wQCwcWLF6V69epy9OhRXx8KEBI0hg0bNszXh4EioL/0H+SSAAIZfRiAQEIODPwP8RveQr8LBI5Svj4ABL9PPvlE5syZY6rrrAo7rbhbs2aNhIWFmZvS+4iICPNYE5Hs7OxC9zto0CCJjY29Y/lPP/0kX3zxhZw6dcokM2PHjjUJh4qMjJTw8HCn9Q8dOiSvvfaa/bVKlSrJzZs3ZcqUKTJmzBjp3LmzdO3aVUqVorkguJUpU8b8IaBtAYDn6R9MxJbARH/pXeSSAAIZfRiAYEEOjFBC/IY/oN8FAge9LTxu1KhR5qbVfW+++aZs3rzZ/tqWLVuckoWSJUu63IcmNNevX5cHHnjAvkwrunr06OG03sKFC2X+/Pnmvnbt2rJ161aTeKxYsUIaNmwopUuXtidDFk1gNm3aVGjykZmZWaRzBwKJto+MjAxfHwYQMvr27evrQ0AR0V96F7kkgEBGHwYgWJADI5QQv+EP6HeBwMEw8vAarezLzc11WlaiRAl7QqJJQ0HJiTUMj6MdO3ZIkyZNnJZpYrJgwQKpU6eO2Z9WAOoQvd9++639/fInJ/pcExMd8uepp54yw/LoUEAjR46U8+fP29cpaO4bIJjosFZ9+vQxFbzjxo2TypUrS0xMjCQnJ9vngFKrVq0yCX9UVJS5nzp1qrRr186nxw4EmkmTJpn2pvFN/3jSmKZtqlOnTnLkyBEz5FuLFi2kQoUK8vTTT5sKdwtt0PfoL72PXDL4paWlyYgRI2T27NlSrVo1KV++vPTr18987trefvnlF5k8ebL5LKtUqSJDhgyRvLw8+/b62ekXj9pvav/53nvvme0Af0AfBl+gX0VxIwdGqCF+w9fod1EU5IDex8V2eI1W5enFAx3S5oUXXpAaNWqYSj5NGO6WnOhyHTbF0YEDB0xwcaT7tvZn0f1aCYU+1iRp/PjxpqOx6AWMnj17mkrFZcuWyeeffy7nzp0znYy1nVYDVq1aVfr3719MPxHAf6Wmppp2o21W2+769etl+vTp5jV9ru1g1qxZZu4gTf6XLl3q60MGApb+IaxzrM2bN09Onz5tktxu3bqZZXPnzjXLNP7oH1KKNuhf6C+9h1wyNKxcudJ81rt375aDBw/KyZMnzZcEVpGS9ol79uwxc1cePnxYJkyYYF7TLws++OAD+eGHH+TChQsyc+ZMWbx4sY/PBvh/9GHwFfpVeAI5MEIF8Rv+gn4X7iIH9DIb4AW3b9+2NW/e3Fa/fn3bb7/9Zp6rrVu32tq2bWsed+7c2bZ582bb999/b6tcubKtRo0atoYNG9qaNWtma9y4sS06OtqWlJRka9Soka1u3bq2xMREW0JCgq1mzZr290lNTbW1adPGtnPnTltubq5t7dq1tlq1atn27NljXs/OzrY99NBD5j0yMjLs212+fNn28MMPm2V5eXm2nJwcW0pKiq1v377m9aysLFv79u29/FMDvE/b3VtvvWXamqNdu3bZoqKibDdv3rQ999xzpq05+vHHH+1tGcC9mThxomlvmo5pXHJsb7ps2bJlTss0TinaoH+gv/QucsnQsHDhQltcXJz5GVpOnTplK1u2rPl8W7du7bT+9u3bzeep9DNOT093en3GjBmmnQK+Rh8GX6FfRXEjB0YoIX7DH9DvoijIAb2POdvhFTrsRGxsrAwdOtQMOaFD5OpQN1q5p0PZWPRx9+7d5cUXXzRzkhRGt9Wb43Apun8dEmP06NGmkk+H0NEKngYNGtj3r6+/8sorTvsqW7aspKeny5w5cyQlJcVUHrZq1Uo+/fRTeyWgvhcQKtq3b+/0/NFHHzVtVqsndW6qDz/80GfHBgSjZ555xv64XLlyJu7oUHCOy86ePWse0wb9C/2ld5BLho42bdpIRESE/bmO9qFDau7du1eGDx/utG7FihUlJyfHDIWn1fpPPvmkD44YuDv6MPgS/So8gRwYoYD4DX9Cvwt3kQN6Fxfb4XE6pIkOQZGVlWXmGFm0aJEMHjzYDJd748YN+5A4mmRoAqCJgTX8jg5zocNV6Hw2mmzo0Dvx8fHSpUsXefnll01SkV/v3r3NzZXC5qdp3LixOSZX9HgcOyYg2OUf5koTe523RdvptWvX7vjj4cqVK14+QiB4aCzLH8+0DUZGRrpcnzboX+gvPY9cMrTblLp69ar5fPXLAVeuX79u7vXLJke0N/gD+jD4Gv0qPIEcGMGO+A1/Q78Ld5EDehdztsOjtBJG53dYsWKFSUzUV199ZZIKDQKanFiVgNrIHav6tCrv9ddfl+bNm5uEZvPmzfLHH3+YREfnpGnZsqWcOHHC5ftOmzZNjh07dsdyx/3npxWA0dHRUq1aNTP/TkJCgrnVrFlTnn32WdMRAaEqIyPD/GdtYmKiNGvWTDZu3Oj0ev7nADyHNujf6C+LF7kkdG65o0ePSosWLQpcR3/uDz/8sGzatMlpOe0NvkYfBn9EvwpPIAdGMCF+IxDQ78Jd5ICexcV2eLx6RisBk5KS7Ms0MZk5c6aprHMcdker9ByTBx2qJzU1VXr27ClxcXESHh5utq1fv74ZVkf3qVWCrixbtkwuXLhwx3INQPmHyLDocbz99tty/Phx0+kcOnTI3P7991+TXAGh5Ouvv5Y///zTtMvt27fLgAEDZPLkyVKiRAkZO3asvP/++6ZSV6vd9I8HXReAd9AG/Qv9pWeRS4aeVatWyfLly81nqV8G9OrVS4YNGyYxMTGFbqftTYfg1G30S0UdRvHAgQNeO27AFfow+AP6VXgCOTCCGfEb/oh+F+4iB/QuLrbDp/IPu+OYnOi8EDrHzP79+5220XUyMzNlw4YNZh4ad1SqVMkM+eOKNdRPQQqrIgSCTevWrU0g1TmhXnrpJXn33Xdl0KBB5jWdo2rSpElmLioNztoWx4wZ43IYLADFjzboX+gvfYtcMvjoF5BLly41c8Y98cQT0q1bN5k+ffpdt9Mvm/RLTZ2XTv+z5+zZs9K/f3/aG/wafRi8gX4VnkAOjFBG/IYv0O/CXeSA3hVms8qwAB977LHHZPz48dK1a1fzXJOWhQsXys8//2yq8fRXVZfpfBFaDThixAjTSbjStGlTk0xoB6D3WtGlVYf6WPeh1Tl9+vRx2kYrwTQZqly5sqkIs+al0G10+CCdx2Lbtm1e+EkAvqPDY7Vv394MPaVJmiunT5++Y16XcePGyaVLl2T27NleOlIgdNEG/QP9pf8hlwx8aWlpZjhEvXeXq/amlfs6RN6oUaOK8SgBz6APgyfQr6K4kQMDzojf8DT6XRQFOaD3cbEdQeny5csSFhZmEgyt8LMSjbtto0lJZGSk2RYIJVqhlpOTI40aNTLDyeiwWAUlcDqHlM4zlZycLA8++KAJ3N27dzdVk02aNPH6sQOhhjboW/SXoYFcMvC+END/6oiPjzf3UVFRZhjOgQMHmv8qio2N9cjxAv6KPgwW+lUUF3JgwPOI33BEv4v7QQ7ofXfvsYEApHPZeGMbIFi0bdvWzO80depUOX/+fKHraoI3ZcoUU82mVbKJiYmyZMkSkjfAS2iDvkV/GRrIJQOP/lePzlNYt25d858/DRo0kNWrV/NlAEISfRiKA/0qHJEDA55H/IYj+l34Cjlg0fCf7QAAAAAAAAAAAAAAuKmEuxsAAAAAAAAAAAAAABDquNgOAAAAAAAAAAAAAICbuNgOAAAAAAAAAAAAAICbuNgOAAAAAAAAAAAAAICbuNgOwGOysrKkSpUqcvv27WLfd79+/WT48OHFvl8AAEIZsRsAgOBEjAcAIPAQv4HAwMV2IETNmzdPfv/99wJf37VrlwwdOlRycnLueM1ms7lcduPGDbl69ap9WYkSJSQyMtLc34uPP/5YIiIipEKFCiaJiI6ONrdy5cpJmTJlZO/evfZ1w8LCpGzZsi73s3btWpk7d26B75OXlydDhgyRHTt23NNxAQDgD4jdxG4AQHAixhPjAQCBh/hN/AYsXGwHQtSSJUskMzOzwNfPnDkjn332mQnO+fXu3VvCw8OlYsWKUrVqVYmNjTX3cXFxEhUV5bSuBu17NWrUKBOoL168KNnZ2SYR2bZtm1y6dEkuXLgg9evXd1q/ZMmSLvezceNGWbx4cYHvo+ekycKpU6fu+dgAAPA1YjexGwAQnIjxxHgAQOAhfhO/AUsp+yMAIUUDqVbKaZB1RYOyclU1l5aWJt98880dy0+cOCH16tUrcjLguO7OnTtNNd/Ro0clISHBJB+uzsEVXa7bFnRu1nnda0UgAAD+gNhN7AYABCdiPDEeABB4iN/Eb8DCxXYgRJUqVUo++ugjc3MMxvmDpKtgXlAQvn79uhnWxqIB2Z1kwNGXX34p1apVM8PxdOjQwSzr1q2bqRbUxECr8caOHVvguW3ZssVUBjqeh+P56Tw3RT02AAB8gdhN7AYABCdiPDEeABB4iN/Eb8BC2QkQojQQDh48WG7evGmCtt40QOpzDeo6L0tB88dYTp8+LeXLl5fc3Fx7tV7p0qWd1ilKdduGDRtk5cqVkpGRIevXr5f09HSzfPny5aaaTt+3e/fuBe5bz61hw4bmXG7dumU/N32s1YbXrl2767kBAOBviN3EbgBAcCLGE+MBAIGH+E38BixcbAdClAZGrVArqIrOqkrT9Qqi216+fFnKlCljn4fGsfKuKNVtmoQ8//zzsmjRIklMTJQFCxZIz549zb0mGveyPz1mPTa9FZYwFHZuAAD4G2I3sRsAEJyI8cR4AEDgIX4TvwELw8gDIUoDYU5OjgngGjQ1MVBamaYVa+fOnbOvVxDdxjE4a/Bv06aN03scPnxYYmJizHskJyfLO++843Jfx48fl9GjR8vq1avlu+++k06dOtmHttHKu969e8uOHTskNTX1rlVz+r5aBagVelbCo8ep52XdSAYAAIGG2E3sBgAEJ2I8MR4AEHiI38RvwMLFdiBEaSBMS0szFW7W0DQ6vI2r9RxpwLeq2azKOh16Rh9rpdy4ceNk165d5rkG7Pj4eNm9e7dZ30o4XImOjpZGjRrJjBkzJC4uzuk1nVNm//79JsBb7pYMHDhwQKpWrWpPBhy3LejcAADwZ8RuYjcAIDgR44nxAIDAQ/wmfgOWMBuTKgAhSavPNKhbgX3evHkyadIkUwFnzTGj8g+DM23aNElJSbG/HhERYYa20ZsOdxMVFSUVKlSQGjVqmOFp+vXrJ0eOHCn249+6dauZz6ZOnTp3vGbNI2MlH5oY1K1b1yQUtWvXtp+fnru7w/AAAOArxG5iNwAgOBHjifEAgMBD/CZ+Axb+sx0IUfmr4LT6TgO7BsfCAuTIkSPNcDSFVdE5zg9TFFrJN3PmTFmzZo0cO3bMJC5KA7gmG02aNJGBAwdKUlKSy+3zJzBWZeG9nB8AAP6K2A0AQHAixgMAEHiI3wAs/yu5ARDyrCFr7kYr7KxEoEePHvL3338Xus+i0Plkzp8/L0uWLJH//vtPsrOzze3kyZPm/bSi74033pClS5fe0/6s4yAJAAAEE2I3AADBiRgPAEDgIX4DoYv/bAdCiFau7dy5U8LDw00Vmg7zokPC6E0r3K5cuSL79u0zwVOX3bhxw8wzo8tjYmKkWbNmTvs7dOiQ5ObmFvh+DRo0kKlTp7p1jDk5OWYIm3Xr1pnhcvKrWLGiSUIyMzNNZZ4mBhYdzkaPWc9NExY9B63a0+NUe/fulUuXLpnz0+V6bnr8ul7Hjh3dOk4AALyB2E3sBgAEJ2I8MR4AEHiI38RvwBXmbAdCSF5enqmccxz+RRMDHRZGb9b8MtotWAmB3vRxr169ZP78+U770+RAh6Np165dsR7n448/buaLSU5ONu+hjy1nzpwxicLw4cMlNTVVXn31VftrrVu3lr/++ss81mRAz03v9bysoW+s+WSsc9Nb9erVTSIBAIC/IXYTuwEAwYkYT4wHAAQe4jfxG3CFi+1AiNHhYzQhsOZXuR9NmzY11WxWMqE33acVcJU+X716tQnU90qr42bNmiXp6ely8OBBUx2niYsGdasCUOeU6dKlyx1Ve3oMen5WYgMAQKAjdgMAEJyI8QAABB7iN4D8uNgOoNhohZ52KZoAEIwBAPB/xG4AAIITMR4AgMBD/AYCExfbAQAAAAAAAAAAAABwE6UxAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAAC4iYvtAAAAAAAAAAAAAACIe/4PdZD/a9X2gmYAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue\n", + "\n", + " ratio_df = mall_df[\"๋ณด๊ด€ ์ •๋ณด\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"๋ณด๊ด€ ์ •๋ณด\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๊ตํ™˜/๋ฐ˜ํ’ˆ ์ •๋ณด\n", + "- ์ œ๊ณต ํ˜•ํƒœ ํŒŒ์•…" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB9sAAAH/CAYAAAD38r1XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAaZ1JREFUeJzt3Qf8XfP9P/BPhkTIlkTEFmKUnz3KzyqtGBV7tYSW2rtNa9emlFqlVEOtVmOrmkERe9QKMaIiagRZCCH3/3h/+r/f33cmOeSb7/fe7/P5eNxfvvecc8899/7qvs45789oVyqVSgkAAAAAAAAAmG3tZ39TAAAAAAAAACAotgMAAAAAAABAQYrtAAAAAAAAAFCQYjsAAAAAAAAAFKTYDgAAAAAAAAAFKbYDAAAAAAAAQEGK7QAAAAAAAABQkGI7AAAAAAAAABSk2A4AAAAAAAAABSm2AzTi3nvvTe3atUsPPPBASx8KAG3MW2+91aYyaKONNkp77rlnSx8GAAAAVMW1/5gxY/K1drdu3dLCCy+c3nvvvTQ3XXHFFfmzQVvRsaUPAAAAAAAAAPj2tt9++/Tll1+mCy64IH311Vepc+fOLX1IUNX0bAdmKlqgRUs0AAAAgFlxHwEA6orR3KKn+dzwySefpBdffDGddNJJ+X333nvv1KtXr7ny3tBWKbYDAAAAAABAhZs8eXL+d8EFF2zpQ4E2Q7EdAAAAAAAAKlypVGrpQ4A2R7Ed5qIvvvginX766WmFFVZI8847bxowYEA68MAD89AuIYZZ69OnT55H5YwzzkjLLrtsmm+++fL2Mb/KjBkz8nZ//vOf06qrrpq6dOmSllxyyXTOOec0eK+//vWvadNNN009e/bM7xXb/+Uvf2l0eLfbb789XXrppWnQoEGpQ4cO6bDDDsvD2sS6sNdee+W/4/HWW2/VvPb1119PP/7xj3MruXiPVVZZJQ0fPrxm/bhx4/L+zjrrrEa/j+effz7v8/HHH5/t76j29/TRRx+ln/zkJ6lv3755P88991z60Y9+lBZddNH09ddfN/qecYxbbbVVzfPY7ne/+136zne+k99vkUUWSYceemiaMGHCN/pOx4wZk9q3b5/+8Ic/NPr+N998cz7Wp556qtH1AFDb008/nQYPHpx69OiRFlhggTz823/+8586OXbRRRflfIvzgsjEXXfdNb366qt19hNDx+2www453/bbb7+00EILpW7duqX11lsv3X333Xmbzz77LJ1wwglp4MCBOedWW221dNdddzU4pkmTJqVf/epXaamllsrzvi2xxBLpmGOOSZ9//nnNNr/+9a/zMU2fPj2vi2wunytceeWV33hovXiv2HfZjTfemNZff/3Uu3fv1L1797T66qvnc6j4LABQDartPgIAVIq4rjzqqKPydWinTp1yBke+jRo1qibv4vr8kEMOSUsvvXTNveVddtklPfroozU5HdvGdfCDDz5Yk421r2tn59o/RKZfcskl+Vq9fP2/++67p3feeadmmzjWyPmw8cYb18nieM811lgj/fvf/85zukfex7qJEyfWOY5tttkmX2PH+cR3v/vddNtttzU4jssvvzytueaa+To8hqiPewu///3v8/lIfddff32+Vo/9LbbYYunUU09N06ZNmyP/P4LWomNLHwC0pXDebLPNcmAdcMAB+aL1jTfeSOedd156+OGHawI4Wp5F2D3wwAPp8MMPT8sss0wu0EZoRxBGkJ599tm5IPyLX/wi3XfffenII4/MN7vjgjtce+21uQgdN9ujGB43um+44Yb8PAJ05513rnNsf/rTn3JoHnzwwWmdddZJ/fr1q7khv+222+bl3/ve9/K2sS488sgjaYsttsgnGXHSEScBd955Z/rpT3+axo8fn4499th8Y32TTTbJxxPHWt/VV1+dbwCsvfbas/0dRSjX/p7efvvtdPzxx+dQj6J/HGu8X1z4DxkypM77jR49Ov3rX//KN/3L+4jv4qabbsonSnHMH3/8cT75icJFbbP7ncaNhh/84Ae52L7vvvs2+MzXXXdd/sxxYgMAMzNy5Mj029/+NjckGzp0aM7E3/zmNzn7o8FaZGLkdWR45FgUwN9///2cYZEzf//739MGG2xQs7/I9bXWWit17NgxHX300fn1sW1c0I8YMSLfkI+GdHH+Ebke5wc//OEP0xNPPJGL5OGDDz7IN9Lfe++9nLmRe3Es0XDtySefzOcC0eisLG4yxD4je7t27ZqL41FQj88S88d9G1F4iM8R38E+++yTlz300EN5v5Hn8V0BQCWrtvsIAFBJGRw59tJLL6WDDjooXxNHUTuK3eWGaJF5UXCOHI5tokF63KuOTI3i85QpU/I+4t7z+eefn6+nTznllPza5ZZbbrav/aOhfBS4y/ex4/575H1c/8d+oyAe1+3RqD4awkVhPe5Ln3zyyWnFFVesk8XRSD7uXUfDgDg3iOv3+DuUcz+K+XGccf4Q9wriHnvcL4/Cfth///3TH//4x3zeEI3tonB+77335vOOEOcsZVFYL5+DxLlHXLMfd9xx6ZlnnsnvB1WjBMwVBx54YGneeectPf7443WWv/DCC3n5ySefXBo+fHiM8VLq2rVrXl7brrvuWurYsWOpc+fOpX/+85911u21116lxRZbrOb5I488Uho9enSDY9h8881LSy+9dJ1l8X7x+POf/9zocce6OK7apkyZUurfv39p3XXXLX3++ed11h177LH5ON988838/Nprr837qH88X3/9dWmRRRYpnXXWWYW+o1D+nhZaaKHSe++91+CY11hjjfxZ6zv++ONLPXv2LE2bNi0/P//88/N+rrrqqjrbzZgxo/SLX/wir7v//vsLf6e33357fm39zzF16tTSfPPNVzrjjDMa7AcAysaOHZtzpEOHDqXrr7++zro4B2jXrl3poosuynkS21133XUNcnrttdcu9evXrzRp0qS8bOjQoXnblVdeuWZZ+PTTT3OOxfnFEkssUfrPf/5Tsy7ycrnllivtscceNcu23HLLUp8+fUpvvPFGnfe855576mTqCSecUGrfvn1pzTXXbHCucPDBB+fP8Nhjj+XnG264YT6+8nHG86Ysvvjied9hgQUWKO24444Ntnn77bdLI0aMmMk3DACVoZruIwBAJTniiCNKXbp0KT3zzDN1lsc19ODBg3PWXXDBBfnfl156qcG95T/84Q+lzz77rGZZY9e6s3vtH+Ieejy/+eab62z37rvvlvr27Vv66U9/2mC/5fvaZXEtHctXXHHF/Dlqe+utt0rzzz9/aYcddsj37Wv78Y9/XOrRo0e+1zBx4sR8rR/3zut78cUXS3fffXf+u3x+EvcPXn311TrbxflLY98bVDLDyMNcEEOxXHbZZbknV/QAi+flRwwtE72/r7nmmprto/dXudVZ7Z5hMQzLz372szxcam3RajxazcWw6mHdddet0zquLFrHRe+yyZMn11ke25Zbps2OGH4uerRFj7JouVb780SLtri2juFhyscWQ9LU/nwhWtzHPsrvW/Q7CtFaLnqz1xct6GPY2/pD1UWrw2gBGK33Q7QQ/N///d/car+2aLUfLfxq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fLFxkf7444/X2SYa3cVwetGaPnK/vpjjPfYd+6otlh1++OF1lv3qV7/KPfDqi8aAcf5iuDoAKlm13UcAgEoRw7FH0fyCCy5okI0xXPw999yT/45iemRlfWPHjs05GPfPaxelv2k2lq//Y6qXGD21sfeLhvbfJnvjPnqMDBf3y7/66qs666KIP2zYsDwlbDSOj9Hk6k/BGtf6o0ePzp3byiMDQFtiGHmYS2JOlVdeeSVtvPHGudC8/vrr55vh0UIubpLvu+++c+R9osf24MGD0/HHH5+L26uuumpupR7Dvh155JHp9NNPz72944RhjTXWmK2Wc7///e9zy7yYryZu2vfp0ycPBf+DH/wg/c///E+eHz3ma4uTjwjd//znPw1a7sVJyuabb54OOuigfEzf+c53mv07ihv20cstivvDhw9vsD7moIki+JAhQ/JxRavFF198MTcWiCHnYwj4b/udxonKNttsk7+fOdm7EAAiY2Lo9JgXLorrkZ+R1XFTPoaQ/8c//pFb089JMT/6pptumvMucjmGqY9sjBb2ccMhGpjVviCPxm4777xzfs3nn3+eLr/88lwciMZujc0fG6PAxA2NGI4u5n2L84XopR7LItdjWL6yGJovzjvinCHOR6ZMmZJvfMTnPuaYYxTbAah41XYfAQAqRVxvRuPxGPElrk3j+jU6aMU85fE8rlHffvvt9OMf/zhtscUW+Ro2GsrFSDGRgXEv/Oijj66TjVdccUX67W9/m4eDj0c0aC96/R8N3Hfdddd8Xz4K3HFMMYps5HiMFPdNxSixcW4RI8VG1sd5R3yGaPge1/FRXI/G/tHRLobMv/jii9Oee+6Z52qPnuzxvUTjwJi/PkbmgTanBMw1X331VemCCy4orbzyyqXOnTuX+vbtW9pxxx1LjzzySF4/fPjwUlP/Wd5///153dixY2e57tNPPy0dd9xxpSWXXLI033zzldZcc83SrbfeWpo2bVppnXXWycviOEK8Lt63KQ8//HBpxRVXzMc7cODA0nvvvVezbty4caWf/exnpQEDBuT1gwYNKh1zzDGlDz/8sNF93Xjjjfn9Lr744m/8Hc3qe6ovvof555+/NGXKlEbXx/Kf//znpUUWWaTUpUuX0uqrr166+eabS2PGjMnvEd9t0e+0ti+++KLUsWPH0vHHHz9bxwsAkee1M6i+DTfcsDR06NCa51dffXVprbXWKs0777ylXr165dx89dVX67wmto/XNeaEE04oLb744rO97rPPPiudfPLJpeWWWy5ndZwH7LnnnqUXXnihwetGjRpV2mqrrUrdunXLjy222KL0xBNPzPTzTJ48uXTggQeW+vfvn/cf5yHnnntuPkeIbWPf4e233y4NGzas9D//8z953wsssEBeH/kMANWi2u4jAEClePfdd/O1alxrxn3jTTbZJF/3nn322aWlllqqNGPGjNL1119f+uEPf1haeOGF8zV53B8/7LDDSh988EGdfUXObr/99qWuXbuWevfuXbr88ssLX/uXr/+/+93v5lyO6//NN9+89Pe//73ONk3td2bX/mUvv/xyadddd83nG/F5VlpppdIZZ5xRmjp1as02L730Uumggw4qLb/88vk44to9jiPyf3bv38/qXAIqTbv4Py1d8AdoLtESL4Zzj55vLeG2227LPeejFeDAgQNb5BgAYG779a9/nVvtv/XWWy19KAAAAFBIDA+/yiqr5KHVa4sR26K3e4y8FiPAAATDyANVJ+au+fLLL9O9996bnnvuuUaHkG9OMezeNddck4fuiaHqY6g9hXYAAAAAgNYvpijbdttt81RnK620UurSpUt68803c6PymBs9pi4DKFNsB6rO008/nee/WWihhXKP9jghmptijtrTTjstTZ48Oc9RG3PVAAAAAADQ+p1++ulp3XXXzb3XoyPXZ599luc132yzzdJxxx2X7zsDlBlGHgAAAAAAAAAKal/0BQAAAAAAAADQ1im2AwAAAAAAAEBBiu0AAAAAAAAAUFDHoi9oC2bMmJHefffd1K1bt9SuXbuWPhwAmKlSqZSmTJmSBgwYkNq3146uTJ4DUGlkeuNkOgCVRJ43Tp4DUK2ZrtjeiAj9RRddtKUPAwAKGTduXFpkkUVa+jBaDXkOQKWS6XXJdAAqkTyvS54DUK2ZrtjeiGhdV/7yunfv3tKHAwAzNXny5HzBWs4v/kueA1BpZHrjZDoAlUSeN06eA1Ctma7Y3ojyMDYR+oIfgEphGLa65DkAlUqm1yXTAahE8rwueQ5AtWa6SWOAqnHnnXem+++/v6UPAwD4lmQ6AFQ+eQ5AeOWVV9Lw4cNb+jAAmo1iO1Dxpk+fnv7617+mXXfd1VxYAFDBZDoAVD55DkAolUrpySefTNtss03+G6BaKbYDDfTr1y9NmDChwfJLLrkkLbXUUnl+ig022CC98MILDbaJeZeGDBmSevTokQYMGJBOPPHENGPGjFm+57Rp09Jhhx2W37tXr17pxz/+cfrkk0/qbHPHHXekFVdcMXXu3Dl16NAhv8cqq6ySFl988TRs2LD8vssss8y3/PQAUD1kOgBUPnkOwKy8+OKLafDgwWmBBRZI/fv3T4cffnj67LPPatbH37/4xS/SEksskbp27Zq+//3vp3/961+zte+//e1vabXVVsu/89GIKvLh008/rVn/6quvpk022STvt3379mmeeeZJq6++ej6OoUOHpq+++irtsccezfK5AVoDxXagRpwk/e53v0sffvhhg3WXXnppHu5n5MiRadKkSemAAw5Im2++eXr//ffrvH7TTTdNW2yxRfroo4/S008/nR5++OF8MT8rP/nJT/LrX3/99TR+/Ph8E2DbbbetWT927Nh8Unb55Zfnk8Nzzz03TZ48Of3zn//Mr4mTtuOOO24OfhsAULlkOgBUPnkOwOx47bXX0vrrr5922mmn9O6776annnoq/05Ho6dyA6v4DX/zzTfTY489lnNl++23TxtvvHF66aWXZrrv2267Lf385z/PDbwmTpyYHnnkkdy462c/+1nNNltvvXXacccdcw489NBDqVOnTunXv/51zqRoFBZ50LFjx2b/HgBaTIkGJk2aFGOa5H+hrfj9739f6tKlS6lz5875f/8ffvhhzbrPP/+81KtXr9Lo0aPrvOaQQw4p/fznP695fsYZZ5R23nnnOtu8//77pW7dupUmTJjQ5Hs/9thjpUUXXbQ0ffr0OstXXnnl0u23357/HjFiRGnDDTesWRfbdujQoTRlypTSWWedVfrJT37yLT49VDa51TjfC22VTIfKJbsa53uhLZLnULnkVuN8L83noIMOKu2///51lk2bNq20wgorlK655prSU089VerTp09p6tSpdbY5+eSTS9///vdnuu/dd9+9dM4559RZ9swzz5T69++f/448ad++femrr76qWb/++uuX/v73v5eefPLJ0qBBg+qsA6jG7NKzHcj233//3Bo9hoqr74EHHkiLLbZYWm655eos33nnndMtt9xS8/ymm25Ku+yyS51tYsi5ddZZJ911111Nvne8brvttmvQwjFaY5b3H0MVPf/887kVfrSQv+CCC3IL/Ria6LzzzkvHHnvsN/7sAFBNZDoAVD55DkCRnu3x215bTPHx05/+NI0YMSKvX2mlldL8889fZ5v99tsv3X///bnHelP69u2bh6iv7cEHH0xrr712/juGrR84cGC68MILcx7EunfeeSett956eSSV6NUeU40AVDPFdmCWRo8enQYNGtRgeZxIxfBw06dPn+V2se6b7L/8uiWXXDL9+c9/TgcddFAevm7UqFHpyiuvTBdffHEeKi/WAwAzJ9MBoPLJcwBqW3TRRdOYMWMaLH/77bfz8lj/xhtvpK+//rrO+hhWPhpJRXY05Ze//GWeImSHHXbIjbHid/++++5Lf/zjH2u2iYZYt99+e1pooYXS0Ucfna6//vq8z3jstttuc/jTArQ+iu3ALE2dOjX16tWrwfLevXvHVBR5HrdZbTdlypRvtP/ar9tqq63Sc889lz744IP0t7/9LXXr1i23mD/mmGPS3XffnVZeeeXcmjJa8zc2px0AtHUyHQAqnzwHoLbowX7RRRelO+64I/cu//e//52XPfHEE/n5WmutlX/DDz/88DRp0qQ8csoVV1yRe7bH731sM7Oe7SeffHKei/2qq65K99xzT/rkk0/qzPW+/PLL5+XxWx9zuq+xxhp5zvbjjz8+F/R/8IMf5PeJ3u7PPvvsXPpWAOYexXZglrp27drocEKxrF27djVDEM1su7jo/ib7n9nrLrnkkrTlllumGTNm5OHsfvOb3+STyXnnnTfts88+BT4hALQNMh0AKp88B6C2GEL+mmuuycO29+/fP22//fZpgw02yI2f4vk888yTe55HMTwK4yussEJuLBUF8ujtHts0JtYNHjw4vzaGkr/xxhvTq6++mn71q1/l6UaisN6YZ555Jo0dOzb3ht9mm23ysYwfPz7tvvvu6Yc//GFNozCAaqHYDsxSDB/X2HBCMQxRDCMXJ2yz2q7+XHKzu/+mXvf555/XtJj/xz/+kb7//e+nzTbbLN8UOPPMM2tacgIA/0emA0Dlk+cA1LfFFlukxx9/PE2YMCE99dRTaejQobmY/r//+795/cILL5yuu+669O6776a33nor/e53v0vjxo3Lc7svscQSje4zXh/zr0eP9ujhXntkk7322ivvrzHRq/2EE07Ic8XH6CeRDfPNN1/uSR+5EMcHUE0U24FZ2mijjfJFdf2L7RtuuCENGTKkzolW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sKUPAaAq7bBW31QJvk1uze08n5uZLs8BKJPpc55r9KbJdIDmIc+bx7Bhw9IXX3yRzjvvvEbXX3LJJenOO+9MN998c53l1157bbriiivS3Xff3eJ5LnupJJXyWwak2c6uQj3bX3vttXTooYfmkI/Wbauttlr67ne/m5Zbbrn8ZtFK/eqrr05ff/11mtP++Mc/ph/96EeNXsSH2267LX3ve9+rcxEfdt5553TLLbfM8eMBgErVknkeZDoAzBmu0QGg8rX0NfqoUaPSeuutl6688sq0xhprpD59+uT3v+eee/L60aNHp0GDBjV43cCBA/O6pkQBP4oUtR8AUI1mq9j++eefp8MPPzwH/bhx4/IcbPfff396/vnnc2v2GBbuz3/+cw7jmI/tO9/5TrrvvvsqIvSD4AegLWgNeR5cyANA5We6a3QAqPw8Dx988EE6//zzc0O5GCr+3Xffzb3dt99++/T000+nqVOnpl69ejV4XfS8nzJlSpP7Pf3003NjgfJj0UUXnePHDgCtwSzHoIlQ32233dImm2ySXn311dy6rjFxUhABfMYZZ+RW6gcddFDaaKON8txtczL0+/fvn0M/LtD//ve/5/eMk5AI/VhXNPTLwR9z0ABAtWoted6cmS7PAWgLWkumu0YHgMrP89CpU6e0wgorpEsvvbRm2bbbbpsee+yxdNlll6WuXbumiRMnNnhdLOvWrVuT+z3qqKNyA4KyaDyn4A5Am+zZPnbs2NxSPeZmaSr064s52J577rm0yCKLpDkd+iNGjMjzvsXzCP3999//W4V+OfhjvP3yI1oSAkA1aS153pyZLs8BaAtaS6a7RgeAys/zsOyyy6YllliiwfLI+bfeeiuPVPP66683WB+972Oo+6Z07tw5z29b+wEAbbLYvtNOO6V111238I4jTI855pjU2kO/fKyCH4Bq1lryPLiQB4DKz3TX6ABQ+Xkeouf85ZdfnqZNm1Zn+VNPPZXzfIsttkh33313g2ldbrjhhtwAAADautmas701EPoAUB1kOgBUPnkOANVh5513TksuuWQeoSYazH355Zfp6quvTtdee2069NBD87rdd9897bnnnunjjz/O688555z0yiuvpL333rulDx8AKr/Y/tBDD+UL5e985ztps802S3feeWdqDkIfAJrP3MrzINMBoPm4RgeAyjc3r9E7dOiQbr31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2u6444604oorps6dO6cOHTrk91hllVXS4osvnoYNG5bfd5lllmnGT8c3pdgOAAAAAAAA0IRPP/00bbrppmmLLbZIH330UXr66afTww8/nAvus3LKKaekzTbbLD377LP5tccff3zuqR5F+DB27Ni0xx57pMsvvzx99tln6dxzz02TJ09O//znP9Prr7+evvrqq3TcccfNhU/JN6HYDgAAAAAAANCECy+8MK266qpp3333TR07dkwLLbRQuuaaa3JhPAroM3PjjTem3XffPfdqj17rUbD/0Y9+lG677ba8/plnnsm92tdee+28/oADDsj/tm/fPv3+979PgwcPTgMHDpxLn5SiFNsBAAAAAAAAmnDTTTelXXbZpc6yfv365SHh77rrrpm+Ngrn9b3//vupe/fu+e/VVlstPf/887mnfPRiv+CCC3Iv+ii2n3feeenYY4+dw5+GOUmxHQAAAAAAAKAJo0ePToMGDWqwPHqcx7oirr322lxY33PPPfPzmMv9z3/+czrooIPyXPCjRo1KV155Zbr44ovT5ptvntfTenVs6QMAAAAAAAAAaK2mTp2aevXq1WB5796905QpU2ZrHzNmzEi//vWv01VXXZXuvPPO1KdPn5p1W221VX6Uxdzt0av9oYceSnfffXf6xS9+kd55553c4z2GtO/bt+8c+mR8W3q2AwAAAAAAADSha9euaeLEiQ2Wx7Ju3brN8vXvvfde+v73v59eeumlPEf7yiuvPNPtL7nkkrTlllvmAv1OO+2UfvOb36R///vfad5550377LPPt/oszFmK7QAAAAAAAABNiCHkX3/99QbLx4wZk5ZbbrmZvnbs2LFp7bXXTjvuuGO64YYbGu0hX9vnn3+ee7Ufc8wx6R//+Ecu0m+22Wa54H/mmWemO+64I8/tTuug2A4AAAAAAADQhBji/frrr6+zbMKECenxxx9PgwcPrlkWPdHr22OPPdJJJ52U9ttvv9l6r+jV/sMf/jAtssgiqVQqpfbt/6+c26FDhzrPaXn+vwEAAAAAAADQhEMOOSQ9+OCDafjw4bmgPn78+LTLLrukI488Mi2wwAJ5m0cffTR1794992Qve+WVV/Kc7kOHDp2t94le7eeff346+uij8/Mtttgiz9ke7/3FF1/k3u5R+O/YsWMzfVKKUmwHAAAAAAAAaEIM/X7ffffl3u09e/ZMa665Ztp4443T8ccfX7NNly5d0vzzz5/mmWeemmUx9HzM0x5DwNd/rLvuuo32at96663TgAED8vMll1wy/eUvf0kHHnhg6t+/f/r444/zNrQeVVlsHzduXBoyZEjq0aNH/h/jiSee2OiwDQBA6yXPAaDyyXMAqA4yHSClZZZZJs+hPnny5PTuu+/mXubt2rWrWb/KKquk999/Pw//Xha90KdPn56mTp3a4DFq1KgG7xEF+6OOOqrOspiv/cUXX0yffPJJGjFiROrTp08zf1LadLH9008/TZtuumkeVuGjjz5KTz/9dHr44Ydz+AMAlUGeA0Dlk+cAUB1kOsDcE/O6Rw92KkfVFdsvvPDCtOqqq6Z99903z1ew0EILpWuuuSade+65+UQAAGj95DkAVD55DgDVQaYDQBsqtt90001pl112qbOsX79+aZ111kl33XVXix0XADD75DkAVD55DgDVQaYDQNM6piozevToNGjQoAbLBw4cmNc15osvvsiPskmTJuV/Y86FSvDZ1CktfQgAVWny5M6pEpTzqlQqpWohzwGYk2R65eR5kOkANEaet5zWfo0ue6kklfJbFibec0lLHwLMtp7f3y+1VKZXXbF96tSpqVevXg2W9+7dO02Z0njonn766Y3OL7Pooos2yzECQHOInOvRo0eqBvIcgLasWjL9m+R5kOkAVINqyfPgGh2A1u+XLZbpVVds79q1a5o4cWKeN6a2WBbh35ijjjoqHXHEETXPZ8yYkT7++OO0wAILpHbt2jX7MUNbEa2A4oR63LhxqXv37i19OFA1omVdBP6AAQNStZDn0LrJdGge1Zbp3yTPg0yHuUOeQ/OotjwPrtHbHhkBzcN/W9WZ6VVXbI/hbF5//fW0/PLL11k+ZsyYtOeeezb6ms6dO+dHbT179mzW44S2LEJEkMCcVS2t5cvkOVQGmQ5zXjVl+jfJ8yDTYe6S5zDnVVOeB9fobZeMgObhv63qyvT2qcpstdVW6frrr6+zbMKECenxxx9PgwcPbrHjAgBmnzwHgMonzwGgOsh0AGhDxfZDDjkkPfjgg2n48OF5aJrx48enXXbZJR155JF5iBoAoPWT5wBQ+eQ5AFQHmQ4AbajY3qtXr3TffffllnYxLM2aa66ZNt5443T88ce39KFBmxdDR51wwgkNhpACqE+eQ+sm04HZIc+hdZPnwOyS6W2PjIDm4b+t6tSuFLO7AwAAAAAAAABtt2c7AAAAAAAAADQ3xXYAAAAAAAAAKEixHQAAAAAAoIq1xIzCX3/9dc17z5gxo866+s8BKpViOzDHTJo0KS266KLp3//+d0sfCgAAALRprtEB2p5HHnkkrbHGGvnvTTfdNP3973/Pf7/++utpwIABaZFFFklLLLFEGjhwYFp66aXTUkstlZ/H8p49e6aTTjqp0PuNHj06Lbfcck2u32effdKaa66Z1lprrXTvvffWLH/wwQfT9773vW/8OaG1cv7VNnVs6QMAqsd8882XT9S6dOnS0ocCAAAAbZprdIDqdM4556QLL7ww9xYv9xiPHuR33313ateuXX6E+Ldz58757yis/+c//5npfvfff//Uv3//BstHjBiR/vCHP6QPPvggF+ePPvroXEAPkTGdOnWqs/0bb7yRdt1115p1vXv3Tl999VU6+eST069+9av0gx/8IG2xxRapY0flKaqP86+2ya8ZMMfMM8886YEHHmjpwwAAAIA2zzU6QHU64ogj8iN6q+++++7p0UcfrVn32GOP1Sl+d+jQodF9RIH+yy+/TPPOO2/NsuiJu8MOO9TZbvjw4emPf/xj/neZZZZJTz31VC6k33LLLek73/lOzppycb8sCvKjRo2aaTH9oYce+kafHVo7519tk2HkgTkqhh3ac889cwvLY445JvXp0yctsMAC6Ze//GXNHD3h9ttvzydk3bp1y/+eeuqpaaONNmrRYweAtu6KK65Ihx56aDr//PPTwgsvnLp3755++tOfps8++yzn+80335xOPPHEPPxg375904EHHpimTZtW8/o//elP+cZKjx490uqrr56OOuqo/DoAoGW4RgeoXtFTPa7Vamvfvn1NgT2K4E0V28vDytf27LPPppVXXrnOsii0x3XeoEGD8v6iR/vBBx+crr322pr3q19sj+dRaI8h7AcPHpyHmY+h7Q8//PD0ySef1GzT1FzuUOmcf7U9iu1As7jgggvyidJbb72VWzyOHDkynXHGGXldPN97773Teeedl+cwiZOzv/zlLy19yABASunWW2/NWf3iiy+m1157Lb333nu5AB9+/etfpw8//DC99NJLeW6+N998Mx1//PF5XRTiTznllHT99deniRMnpnPPPTddffXVLfxpAIDgGh2g+sTvd/yuxxDt22yzTVp8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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue\n", + "\n", + " ratio_df = mall_df[\"๊ตํ™˜/๋ฐ˜ํ’ˆ ์ •๋ณด\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"๊ตํ™˜/๋ฐ˜ํ’ˆ ์ •๋ณด\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๋ฐฐ์†ก ์ •๋ณด\n", + "- ์ œ๊ณต ํ˜•ํƒœ ํŒŒ์•…" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB9sAAAH/CAYAAAD38r1XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAdRhJREFUeJzt3QeYlNXZOO5Dk9CkiNgVxSC2z4o1QVESwRJii8QYscZeIgYlisZuIpbYozForDFYUJNgQ40ttmhURIktEqyoVAER9n89J7/d/zZgR9kys/d9XfOx884775zZfO5z3vOc85wWZWVlZQkAAAAAAAAAqLOWdT8VAAAAAAAAAAiS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QCL8NBDD6UWLVqkRx99tLGbAkAz9u677zareLT99tunAw44oLGbAQAAAEV3nz9p0qR8X92pU6e0yiqrpA8//DA1pOuvvz5/N2hOWjd2AwAAAAAAAIBvZs8990xffvlluuyyy9JXX32V2rZt29hNgpJnZTuwRDETLWakAQAAAFRn3AAAaheV22KleUP4/PPP06uvvprOPPPM/LmHHHJI6tq1a4N8NjRnku0AAAAAAABQxGbMmJH/XWGFFRq7KdCsSLYDAAAAAABAESsrK2vsJkCzJNkODWzevHnpvPPOS+utt1761re+lVZeeeV01FFH5RIvIcqude/ePe+ncv7556d11lkntW/fPp8f+6wsXLgwn/fHP/4xbbLJJqldu3ZpzTXXTBdddFGNz/rTn/6UBgwYkLp06ZI/K86/7bbbai33dt9996Vrrrkm9e7dO7Vq1Sodf/zxubxNvBYOPPDA/HM83n333Yr3vvnmm2m//fbLs+XiMzbeeOM0evToitcnT56cr3fBBRfU+vt4+eWX8zWfeeaZOv+OKv+ePv3003TQQQel5ZdfPl/npZdeSj/5yU/SaqutlhYsWFDrZ0Ybd91114rncd4ll1yS1l9//fx5q666ajruuOPS1KlTv9bvdNKkSally5bpd7/7Xa2ff/fdd+e2Pv/887W+DgCL8sILL6SBAwemzp07p+WWWy6XhPvggw+qxLQrrrgix7roI0R8/PGPf5zeeOONKteJcnJ77bVXjnWHH354WmmllVKnTp3Stttumx544IF8zhdffJFOP/301KtXrxzzNt1003T//ffXaNP06dPTySefnNZaa628F1zPnj3TKaeckubMmVNxzq9+9avcpvnz5+fXIk6X9xtuuOGGr11uLz4rrl3uzjvvTN/97ndTt27d0rLLLps222yz3J+K7wIAxaLUxg0AoNjEPeSIESPyPecyyyyTY3HEuaeeeqoi7sW9+LHHHpvWXnvtijHlIUOGpKeffroiXse5cc/72GOPVcTIyvewdbnPDxHbr7766nxfXn6v/9Of/jT997//rTgn2hrxPvTv379KTI7P3HzzzdN//vOfvKd7xP14bdq0aVXa8cMf/jDfT0e/Yuutt0733ntvjXZcd911qW/fvvmeO0rUxzjClVdemfsl1d1+++35vjyut/rqq6dzzjknzZ07d6n8bwRNSevGbgA0tyC900475cB15JFH5pvYt956K/32t79NTzzxREUgjhloEfQeffTR9POf/zx9+9vfzgnaCN4RECOgjho1KieEf/GLX6SHH344DRs2LA9wxw14uOWWW3ISOgbYIxkeg9t33HFHfh6BdJ999qnStj/84Q85eB5zzDFpq622Sj169KgYhN99993z8R122CGfG6+FJ598Mu288865sxGdj+gMjBs3Lh188MFpypQp6dRTT82D6TvuuGNuT7S1uptuuikPCGy55ZZ1/h1FcK78e3rvvffSaaedloN7JP2jrfF5MRAwePDgKp83ceLE9K9//SsP9JdfI34Xd911V+4wRZs/++yz3AmKZEVldf2dxsDD97///ZxsP+yww2p851tvvTV/5+jgAEBdjR8/Pl144YV5UtnQoUNzfPzNb36T+wExeS3iY8TuiOcR0yIB/tFHH+V4FjHnL3/5S+rXr1/F9SLGb7HFFql169bpl7/8ZX5/nBs3+WPGjMmD9TGpLvoiEeOjr7DbbrulZ599NifJw8cff5wH2T/88MMcfyMGRltiEttzzz2X+wUxAa1cDDzENSMOd+zYMSfHI6Ee3yX2lPsmIikR3yN+B4ceemg+9vjjj+frRmyP3xUANHWlNm4AAMUYiyOeTZgwIR199NH5/jeS2pHsLp+QFrEvEs4Rj+OcmHweY9QRWyP5PHPmzHyNGHO+9NJL873z2Wefnd/bp0+fOt/nx6T4SHCXj1/HuHvE/bjXj+tGQjzu0WMCfUyIi8R6jEefddZZaYMNNqgSk2NCfIxZx8SA6CPEvXr8HMrjfyTzo53Rj4hxgRhbj3HySOyHI444Iv3+97/P/YeYdBeJ84ceeij3P0L0XcpFYr28LxJ9kLg/HzlyZPrnP/+ZPw9KShnQYI466qiyb33rW2XPPPNMleOvvPJKPn7WWWeVjR49Omq9lHXs2DEfr+zHP/5xWevWrcvatm1b9ve//73KawceeGDZ6quvXvH8ySefLJs4cWKNNgwaNKhs7bXXrnIsPi8ef/zjH2ttd7wW7aps5syZZSuuuGLZNttsUzZnzpwqr5166qm5nW+//XZ+fsstt+RrVG/PggULylZdddWyCy64oKDfUSj/Pa200kplH374YY02b7755vm7VnfaaaeVdenSpWzu3Ln5+aWXXpqvc+ONN1Y5b+HChWW/+MUv8muPPPJIwb/T++67L7+3+veYNWtWWfv27cvOP//8GtcBgNq88847Oaa0atWq7Pbbb6/yWvQHWrRoUXbFFVfk2BLn3XrrrTVi9pZbblnWo0ePsunTp+djQ4cOzedutNFGFcfC7Nmzc0yLvkbPnj3LPvjgg4rXInb26dOnbP/99684tssuu5R179697K233qrymQ8++GCV+Hr66aeXtWzZsqxv3741+g3HHHNM/g7/+Mc/8vPtttsut6+8nfF8UdZYY4187bDccsuV7b333jXOee+998rGjBmzmN8wADQdpTRuAADF6IQTTihr165d2T//+c8qx+N+eeDAgTnmXXbZZfnfCRMm1BhT/t3vflf2xRdfVByr7b62rvf5IcbO4/ndd99d5bz333+/bPnlly87+OCDa1y3fDy7XNw3x/ENNtggf4/K3n333bIOHTqU7bXXXnm8vrL99tuvrHPnznlcYdq0afm+PsbMq3v11VfLHnjggfxzeT8lxgreeOONKudFP6a23xsUO2XkoYFESZZrr702r96KVV/xvPwRJWZi9ffNN99ccX6s+CqffVZ5NViUY/nZz36WS6RWFrPIY/ZclFUP22yzTZVZcuVillysKJsxY0aV43Fu+Qy1uohydLGKLVaRxQy2yt8nZrbFvXaUiSlvW5Smqfz9QszAj2uUf26hv6MQs+ZiNXt1MaM+St1WL10Xsw9jJmDM5g8xU/A73/lOnsVfWczij5l+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80yVc2ICXpTYixn20QeoLvZ4j2vHtSqLYz//+c+rHDv55JPz6rzqYmJg9GWUsAOgqSu1cQMAKDZRjj2S5pdddlmNGBnl4h988MH8cyTTI2ZW98477+R4GOPmlZPSXzdGlt/rx5YvUTW1ts+LSfXfJAbH+HlUgYtx8q+++qrKa5HEHz58eN4KNibCR+W46luvxn39xIkT86K28soA0NwoIw8NKPZWef3111P//v1zovm73/1uHgCPmXIxMH7YYYctlc+JFdsDBw5Mp512Wk5ub7LJJnnWepSBGzZsWDrvvPPyau/oOGy++eZ1mkF35ZVX5hl6sW9NDNR37949l4L//ve/n/7v//4v748e+7dFJySC7wcffFBjBl90VgYNGpSOPvro3Kb111+/3n9HMUgfK9siuT969Ogar8deNJEEHzx4cG5XzF589dVX82SBKDkfJeC/6e80Oiw//OEP8+9naa4oBIDq8SZKp8decZFcj1gacTsG7KOE/N/+9rc8w35piv3RBwwYkGNfxOgoUx9xMmbdxyBETDarfJMeE9/22Wef/J45c+ak6667LicOYuJbbXvLRkWYGOSIEnWxF1z0HWKVehyLGB+l+spFub7og0T/IfomM2fOzIMh8b1POeUUyXYAikKpjRsAQLGJe8uYKB6VX+I+NO5VY2FW7FMez+N+9L333kv77bdf2nnnnfP9akyYi4oxEQtjDPyXv/xllRh5/fXXpwsvvDCXg49HTF4v9F4/JrP/+Mc/zuPxkeCONkX12IjnURXu64rqsNHHiAqxEfOj/xHfISa5xz17JNdjYn8ssIuS+VdddVU64IAD8l7tsZI9fi8xSTD2r48KPdAslQEN6quvviq77LLLyjbaaKOytm3bli2//PJle++9d9mTTz6ZXx89enTZov7TfOSRR/Jr77zzzhJfmz17dtnIkSPL1lxzzbL27duX9e3bt+yee+4pmzt3btlWW22Vj0U7QrwvPndRnnjiibINNtggt7dXr15lH374YcVrkydPLvvZz35WtvLKK+fXe/fuXXbKKaeUffLJJ7Ve684778yfd9VVV33t39GSfk/Vxe+hQ4cOZTNnzqz19Th+4oknlq266qpl7dq1K9tss83K7r777rJJkyblz4jfbaG/08rmzZtX1rp167LTTjutTu0FgMoitleOR9Vtt912ZUOHDq14ftNNN5VtscUWZd/61rfKunbtmmPoG2+8UeU9cX68rzann3562RprrFHn17744ouys846q6xPnz45bkef4IADDih75ZVXarzvqaeeKtt1113LOnXqlB8777xz2bPPPrvY7zNjxoyyo446qmzFFVfM148+ycUXX5z7C3FuXDu89957ZcOHDy/7v//7v3zt5ZZbLr8esRoAikmpjRsAQLF5//33831p3FfGePGOO+6Y73FHjRpVttZaa5UtXLiw7Pbbby/bbbfdylZZZZV8/x3j4scff3zZxx9/XOVaEW/33HPPso4dO5Z169at7Lrrriv4Pr/8Xn/rrbfO8Tnu9QcNGlT2l7/8pco5i7ru4u7zy7322mtlP/7xj3O/I77PhhtuWHb++eeXzZo1q+KcCRMmlB199NFl6667bm5H3KdHO6IfUNdx+yX1KaAYtYj/09gJf4D6FDPyopx7rHZrDPfee29eOR+zAXv16tUobQCAxvSrX/0qz+R/9913G7spAAAAsEhRHn7jjTfOpdUri+pssdo9qqxFJRiAcsrIAyUp9rD58ssv00MPPZReeumlWkvI16cow3fzzTfnEj5Rqj5K70m0AwAAAAA0XbEd2e677563Ndtwww1Tu3bt0ttvv50nkMfe6LFNGUBlku1ASXrhhRfyPjgrrbRSXtEeHaOGFPvSnnvuuWnGjBl5X9rYswYAAAAAgKbrvPPOS9tss01evR4LuL744ou8r/lOO+2URo4cmcebASpTRh4AAAAAAAAACtSy0DcAAAAAAAAAQHMn2Q4AAAAAAAAABZJsBwAAAAAAAIACtS70Dc3BwoUL0/vvv586deqUWrRo0djNAYA6KysrSzNnzkwrr7xyatnSnLpyYjsAxaq5xXYxu/n64osv0pVXXpmOP/741Lq14Sqg+DS3mF1XYjsApR7bW5TFmVTx3//+N6222mqN3QwA+NomT56cVl111cZuRpMhtgNQ7JpLbBezASh2zSVm15XYDkCpx3ZThWsRs+zKf3nLLrtsYzcHAOpsxowZ+Sa2PJbxP2I7AMWqucV2Mbv+HHPMMenOO+9MrVq1qnJ8yJAh6Te/+U2N86+99tr0xhtvpFGjRtXp+i+99FI644wz8r+xcnGbbbbJz3v16pVfjxUhJ510Uvrb3/6WPv/887wypHfv3umzzz5LPXr0SK+99lp67rnnKs4HKDbNLWbXldgOQKnHdsn2WpSXs4ngrwMAQDFSmq0qsR2AYtdcYruYXb+/29NPPz2deOKJSzw3kuzXX3992m677er0v0MkUPbaa690ySWXpL333jvNmTMn/epXv0o//OEP09tvv50T/L/4xS/yv7HC8dNPP00DBw5MO+20U7rwwgtzQn/ChAlpk002WUrfFqDxNJeYXVdiOwClHtttHgOUnHHjxqVHHnmksZsBACwF4jpAw4qVGxtttFGaOHFind/z4IMPpq233jrtu+++qU2bNjmZctFFF6Vp06alN998M5/z1FNPpQMPPDC1a9cul2DcY489cvI99mqPJP3IkSPr8VsBAA3tH//4R7rrrrsauxkA9U6yHSgZ8+fPT3/605/Sj3/8Y3tjAUCRE9cBGkesUp87d2469dRT6/ye5ZdfPk2aNCl9+eWXFcdefPHF1L59+7TGGmvk51tttVW65ppr0uzZs9O7776bS9rHyverrroqr3Jfa6216uX7AAANa8GCBXki3u677546d+7c2M0BqHeS7cAixb55U6dOrXH86quvzgMhsU9Fv3790iuvvFLrAM3gwYNzh2rllVfOe/UtXLhwiZ8ZgzrHH398/uyuXbum/fbbL+/nV9lf//rXtMEGG6S2bdvmlRDxGRtvvHEexBk+fHj+3G9/+9vf8NsDQGkR1wGIPdF33nnnnBzv2bNnOvTQQ/Oe6d/ULrvskvr06ZP3ab/hhhtyWfijjz463XPPPelb3/pWPifKxcff+vibHsn1k08+Of+9j1XthST2AYD/36uvvprj6nLLLZdWXHHF9POf/zxXjSkXP8dWLhH3O3bsmL73ve+lf/3rX4u95ksvvZS6dOlS4xH3jPFZlVeub7HFFnlyXdzLLbPMMqlv375plVVWSUceeWRaZ5110g477FCv3x+gKZBsB2qIlQYx4PHJJ5/UeC1WIowePTqNHz8+TZ8+PXecBg0alD766KMq7x8wYEAexIm9+F544YX0xBNP5IH5JTnooIPy+6PU4JQpU/KAfsyCLPfOO++k/fffP1133XW5s3jxxRenGTNmpL///e/5PV999ZXygwBQibgOQFh//fVTy5Yt877t77//fv5bPnPmzLTrrrumsrKyb3TtuO4pp5yS/5b/8Y9/zCVjI+7885//rDgnSstHzInPfv311/MErFjVHvGle/fuOfEfk7Ni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sh0AAAD4RubOnZtOPvnkdMMNN6SePXvmVZVDhgxJe+65Zxo1alRjNw+gwbz//vvp1FNPTRdeeGGtq9pjJfsWW2yRWrRokdZYY438NzImKS3OLrvskv7whz+kDTfcMLVq1SqtsMIK6corr8yr1b/88st8zlNPPZVXtrdr1y6vfN9jjz3yueWr4keOHFlv3xkAoDmTbAcAAAC+kUcffTStvvrqeSVlZfvss08aO3Zso7ULoCGVlZXl1eYXXHBB6tGjR43Xl19++fTqq69WOfbYY4+lLbfccrHXjaR5dVE1pH379hV7sEeJ+agwEiXp33333by6PsrHX3XVVWngwIF5iw8AAJY+yXYAAABgiZ577rm0884752RRrF6P/Yg/++yz/NrEiRNT7969a7ynV69e6c0338xl6Gszb968NGPGjCoPgGIVq9njb2GsRK/NSSedlP7+97+nvfbaK91111153/WHH344/f73vy/oc2KrjoMOOigNGzYsVxIp/+y2bdumb3/72zm5HtVGNt5447yqPVbaAwBQPyTbAQAAgMVaf/31c0In9m2PEslPPPFEmjlzZtp1113zSs5Zs2alrl271nhft27d8uux0rI25513XurcuXPFY7XVVmuAbwOw9L300kvppptuWuzWGTFZ6ayzzkqPP/54uvHGG9ODDz6YPv/88zRhwoQ6f06cu/XWW6dtt922Smn4ZZddNo0ePTr/jX799dfTfvvtl1e1xySp7t275wlSsdp+nXXWSbfeeus3/r4AAPzP/+oMAQAAACzCL37xiyrPYz/g2J89/o0EU8eOHdO0adNqvC+Oxb7EHTp0qPW6I0aMSCeccELF81jZLuEOFJs5c+akAw44ICe7Y8/02ixYsKCiOkiUko9/w3333Zf3V7/nnntyAn1xrr/++pxgv/TSS9Puu+++xDbFeTE56sQTT0wff/xxmjRpUnrttdfyyvtIum+66abf4FsDABAk2wEAAICCRbni2Kc9VlFG2eRY0VldJHailHybNm0WeY14ABSz559/Pv+969+/f8Wxr776Kie8u3TpkgYMGJAOOeSQ9N///jeNGzcuT0IqFxVCDjzwwLzafHHJ9igLH/u7P/3003mi05LEqva4dkxgiv3bH3nkkdyWbbbZJu2zzz7p3nvvlWwHAFgKJNsBAACAgn3wwQe5VPGGG26YlltuuZxoiv3Z11577Ypz7rjjjjR48OBGbSdAffvud7+bvvjiiyrHHn300bwne6xiD+VJ9sqJ9nLvvfde3q4jxNYb1c+Jfd3/8pe/pH/84x+LrBRS26r2J598suKa5Xu7h1atWlV5DgDA16dXBQAAACxWlCC+6KKL0ieffJIWLlyYXnjhhbxi8ogjjsir2yP5E6WNhw4dmqZMmZLLJd9yyy1pzJgxafjw4Y3dfIBG169fv/z3M/5uxt/J8OGHH+YV65FEj+Mh/rYedthhVd577bXXpjPPPLNOifZw9dVXpx/84AdplVVWyc/33HPPdOqpp+YJAf/85z/Tn/70p/w6AADfnGQ7AAAAsFiRRJ8wYUIuOdypU6e03377pYMOOihdcMEFFedEUj32HY4yyJ07d87JoVjJ2aNHj0ZtO0BT0L59+1zKPVatx0r4+Fsa/86bNy9PYCr/WxnHO3bsWOW9UTUk/u7G8eqP2PO9+qr2yy67LI0YMaLi2KhRo3IJ+TXWWCPttdde6fLLL08bbbRRA31zAIDSpow8AAAAsFhRKv66665b4nnDhg3LD4Dmbvvtt68oIV9uhRVWSFdeeeVi33fbbbfVuid8Xf3nP/9J5557blpppZUqjkVSvi5/wwEAKJxkOwAAAABACejTp09+AADQMJSRBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKFDrQt8AAAAAAFBu2rjLGrsJUJAuA49p7CYAACXCynYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAAACgQJLtAAAAAAAAAFAgyXYAAAAAAAAAKJBkOwAAAAAAAAAUSLIdAAAAAAAAAAok2Q4AAAAAAAAABZJsBwAAAAAAAIACSbYDAAAAAAAAQIEk2wEAAAAAoBn56KOP0kEHHZRWWWWV1KVLl7Ttttumhx56qMo5V199dVprrbVSp06dUr9+/dIrr7zSaO0FgKaqqJLtOgAAUFrEdgAAAGh4u+yyS+rWrVt6/fXX0yeffJKOOOKItPvuu6cJEybk16+55po0evToNH78+DR9+vR05JFHpkGDBuX7eACgSJPtOgAAUFrEdgAAAGhYb7/9dnrzzTfTqFGj8sT2Nm3apP322y/tsMMO6Yknnkhz585NJ598crrhhhtSz549U8uWLdOQIUPSnnvumd8DABRhsl0HAABKi9gOAAAADS8mvcc997vvvltxLCa4v/zyy6lv377p0UcfTauvvnrq06dPlffts88+aezYsY3QYgBouoom2a4DAAClRWwHAACAhhfbuJ177rl5K7eYzH7TTTflynNnnHFG2nTTTdPEiRNT7969a7yvV69eedL8/PnzF3ntefPmpRkzZlR5AEApK5pkuw4AAJQWsR0AAAAaR0xkj4nusXXb7bffnifCv/rqq+mLL75Is2bNSl27dq110nxZWVmaPXv2Iq973nnnpc6dO1c8VltttXr+JgDQuIom2R50AACgtIjtAAAA0LAeeOCBtM0226SDDjooTZgwId1zzz25ytw777yTt27r2LFjmjZtWo33xbEWLVqkDh06LPLaI0aMyFXryh+TJ0+u528DAI2raJLtOgAAUFrEdgAAAGh4p512WrrgggvSD37wgyoT26+77rp8rx4/R0W56iZNmpSrzbVp02aR127btm1adtllqzwAoJQVTbJdBwAASovYDgAAAI2jZcuaqYH//ve/+X56r732yvfe1e/J77jjjjR48OAGbCUANH1Fk2wPOgAAUFrEdgAAAGhYhx12WDr++OPT/fffn7788sv8GD9+fNpjjz3yxPioJDdy5Mg0dOjQNGXKlLRgwYJ0yy23pDFjxqThw4c3dvMB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aVkasT1Wscd7O3TokNq0aZP22GOPtPfee6f7778/vz5lypR0+eWXpxtvvDH16NEjn3P88cfnLWOiig0A0LTux0P79u3TxRdfnD766KM0e/bsvEf7JptsUvF6xPNzzz03vf/++7ni3NixY3MFGwCgqhZlZWVl6Wv67ne/m0u8jhgxouLYtddem2+y//Wvf6ViFZ2HKHs3ffr0XCKvqRvz7CeN3QSAkrbXFsun5hLDxPamQWwHqF9i+zeP7UOHDk3bbbddOuigg9LVV1+dV97dfffdVc6JajXXX399Th40hZgtvlJsiulv1bRxlzV2E6AgXQYe02xidmOrr9gurlOMiim2A6nOMWyJK9t/+MMf5nKttXnrrbdyB6CygQMH5lKwAEDTJLYDQGlpyNgeJeJjFdwLL7yQt4QJEydOTL17965xblSqidcWZ968eXkAo/IDAEqV+3EAKD1LTLbHDfNGG22UDj300FwyprIo6XrzzTdXORZ7rcZxAKBpEtsBoLQ0RGyPkvAxkz9K2sb+7IcffnjFti6zZs3K28FU161btzRz5szFXve8887LKwXKH6uttlpB7QKAYuJ+HABKT+slnfCb3/wm3/BedtllufTbvvvum0vZxE32+eefn/r165eeeuqptPHGG6fXXnstPf300+nhhx9umNYDAAUT2wGgtDREbH/jjTfyvwsWLMir1Y855pj06quv5hLyHTt2TNOmTavxnjjWqVOnxV432nnCCSdUPI+V7RLuAJQq9+MA0AxXtofjjz8+3/A+++yz+cZ6vfXWSxdddFGeVffKK6+kzTbbLJezieMvvvhi2mabbeq/5QDA1ya2A0BpaajY3qpVq3zNK664It12220Vq/TefPPNGudOmjQp9enTZ7HXa9u2bU4wVH4AQClzPw4AzWxle+jQoUMqKyvLJeJi9t1RRx2VTjnllFxG7owzzki//e1v67+lAMBSI7YDQGlp6Ng+ZcqUvDIvxP6yJ598ck4cVE6W33HHHWnw4MFL9XMBoNi5HweAZriy/d///ne+Yb744ovT8OHD04cffpj3ixkzZky6/vrr8z4zf/vb3+q/tQDAUiG2A0Bpqc/Yvttuu6W77747zZ07N3311VfpkUceyXvNnnbaafn1NddcM/30pz9NBxxwQPrss8/Sl19+mVfovf766+mQQw5Zyt8UAIqb+3EAaIbJ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PfdMo0aNarT2AkBTU5TJdh0AACgtYjsAAAA0rLKysjR06NB0wQUXpB49elR57dFHH02rr7566tOnT5Xj++yzTxo7dmwDtxQAmq6iS7brAABAaRHbAQAAoOHFhPfevXunXXbZpcZrEydOzK9V16tXr/Tmm2+m+fPn13rNefPmpRkzZlR5AEApK7pkuw4AAJQWsR0AAAAa1ksvvZRuuummRVaNmzVrVuratWuN4926dcuT5mfPnl3r+84777zUuXPnisdqq6221NsOAE1JUSXbdQAAoLSI7QBQHCLujhkzJg0cODCtuOKKafnll0+DBw9Ob7zxRpXzrr766rTWWmulTp06pX79+qVXXnml0doMANRuzpw56YADDkijR49O7dq1q/Wcjh07pmnTptU4HsdatGiROnToUOv7RowYkaZPn17xmDx58lJvPwA0JUWTbNcBAIDSIrYDQPGIeHrppZem4cOHp3fffTe99957aeutt04DBgxIM2fOzOdcc801Oa6PHz8+n3/kkUemQYMGpY8++qixmw8AVPL888+nSZMmpf79+6cuXbrkx6677pqry8XPe+21V64yFxXlqov3RbW5Nm3a1Hrttm3bpmWXXbbKAwBKWetUhB2Acl999VUeqI8OQNzgH3jggXl13NfpAMQDAGg4YjsAFI+oFPPYY4/lyW7lTj755Bynn3vuubTNNtvk50899VTq2bNnfn3IkCHp6aefzhVsLrjggkZsPQBQ2Xe/+930xRdfVDn26KOPpqOPPjq9+uqr+XlUkot770i4r7322hXn3XHHHbm6DQBQZCvbyzsAsZKt/HHfffelddddN/8c5ey23377ig5AZToAAND0iO0AUDwiyV450R7mz5+fPvvss7xiLQboV1999dSnT58q5+yzzz5p7NixDdxaAOCbikpyI0eOTEOHDk1TpkxJCxYsSLfccku+V49KNwBAka1sL7QDcPvtt+d95P70pz/lDkCsngMAiovYDgBNdw/34447Lk+S23zzzdPFF1+cy81WF5VoYtJcJOZrq0gzb968/Cg3Y8aMem87AFA3kVRv1apV2nbbbdPUqVNT375907hx41KPHj0au2kA0GSUVLI96AAAQGkR2wGgafn888/zRLjYq/2uu+7Kx2bNmpW6du1a49xu3brlxHyUoo1tYqo777zz0hlnnNEg7QYAFi0qy5WXkK9s2LBh+QEAFHkZ+UI7AO+++26+2X/kkUfSeuut1yjtAwAKI7YDQNP27LPP5olvm222WXr44YcrEugdO3bM28BUF8ei/HxUq6nNiBEj0vTp0ysekydPrvfvAAAAAEtLya1sBwAAAJa+e++9Nx111FHp1ltvzRVnKosS8jfddFON90yaNCmXkq+thHxo27ZtfgAAAEAxKuqV7QAAAED9+/TTT9MRRxyRt3Kpnmgvr04TifXYn72yO+64Iw0ePLgBWwoAAAANR7IdAAAAWKw///nPac8991zkVi5RJn7kyJF5L/cpU6akBQsWpFtuuSWNGTMmDR8+vMHbCwAAAA1Bsh0AAABYrFix/rvf/S7vzV79cdJJJ+VzIqm+xx575JXvnTt3Ttdee21eCd+jR4/Gbj4AAADUC3u2AwAAAIs1atSo/FiSYcOG5QcAAAA0B1a2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAKWcbC8rK0tjxoxJAwcOTCuuuGJafvnl0+DBg9Mbb7xR5byrr746rbXWWqlTp06pX79+6ZVXXmm0NgMAtRPXAQAAoOG5HweAZppsnz59err00kvT8OHD07vvvpvee++9tPXWW6cBAwakmTNn5nOuueaaNHr06DR+/Ph8/pFHHpkGDRqUPvroo8ZuPgBQibgOAAAADc/9OAA002R7586d02OPPZZ22GGH9K1vfSu1a9cunXzyyfn4c889l+bOnZuf33DDDalnz56pZcuWaciQIWnPPfdMo0aNauzmAwCViOsAAADQ8NyPA0AzTba3aNEiPyqbP39++uyzz9Kyyy6bHn300bT66qunPn36VDlnn332SWPHjm3g1gIAiyOuA0Dx6tGjR5o6dWqN48rNAkDT534cAJppsr22vWWOO+64tO6666bNN988TZw4MfXu3bvGeb169Upvvvlm7jDUZt68eWnGjBlVHgBAccb1ILYDQP2YPXt2uuSSS9Inn3xS4zXlZgGgOLkfB4BmmGz//PPP0+DBg3Pgv+OOO/KxWbNmpa5du9Y4t1u3brnDEIMCtTnvvPNyiZzyx2qrrVbv7QcA6ieuB7EdAJa+q666Ki2//PK5rGx1ys0CQHFyPw4AzTDZ/uyzz6a+ffumzTbbLD388MOpS5cu+XjHjh3TtGnTapwfx6IsTocOHWq93ogRI/Ks+/LH5MmT6/07AAD1E9eD2A4AS98RRxyRvvjii5xYr065WQAoPu7HAeCba52KzL333puOOuqodOutt6Ztt922ymtR2uamm26q8Z5JkyblEjdt2rSp9Zpt27bNDwCg+ON6ENsBoGHVpdxsbbE7Ss3Go5xSswDQMNyPA0AzXNn+6aef5pn048aNq9EBCNtvv30O+HEjX1mUv4lSOABA0yGuA0DpsK0bABQP9+MA0EyT7X/+85/zfm/rrbdera9H+ZqRI0emoUOHpilTpqQFCxakW265JY0ZMyYNHz68wdsLACyauA4ApcO2bgBQPNyPA0AzTbbHTLrf/e53+Sa++uOkk07K50Sw32OPPfKMvJgVf+211+YZej169Gjs5gMAlYjrAFA6otxs9dVvdd3Wbdlll63yAADql/txAFh6WpRFPTeqiD3iogMRs+qL4UZ/zLOfNHYTAEraXlssn4pFscWwhlJsvxexHaB+ie3fXKxW/+STT1L37t3z8ygTv+KKK6YXX3wxrb322hXnnXDCCally5Zp1KhRjf59xVeKTTH9rZo27rLGbgIUpMvAY5pNzG5s9fV7EdcpRsUU24FU5xhWVCvbAQAAgKZHuVkAAACao9aN3QAAAACg+EVSvVWrVrnc7NSpU1Pfvn2VmwUAAKCkSbYDAAAABVnUjnTDhg3LDwAAAGgOlJEHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAAAokGQ7AAAAAAAAABRIsh0AAAAAAAAACiTZDgAAAAAAAAAFkmwHAAAAAAAAgAJJtgMAAAAAAABAgSTbAQAAAAAAAKBAku0AAAAAAAAAUCDJdgAAAAAAAIAm6rbbbksvvvhiYzeDWki2AwAAAAAAADQxc+bMSVdccUU6+uijU8+ePRu7OdRCsh0AAAAAAABgMSZPnpwGDx6cOnfunFZeeeV0xhlnpIULFy72Pe+++2469thj01prrZU6duyY1llnnXT11VfXOO/6669PvXr1Sm3atEmtWrVKK664YurTp09ad91101lnnZWT7V27dq3Hb8fXJdkOAAAAAAAAsAizZ89OAwYMSDvvvHP69NNP0wsvvJCeeOKJnHBfnHh9ueWWS08++WSaOXNmuvXWW9OFF16YbrrppopznnrqqTRy5Mj0t7/9LX/OCSeckObPn59ef/31/L4WLVqkn//85w3wLfk6JNsBAAAAAAAAFuHyyy9Pm2yySTrssMNS69at00orrZRuvvnmdPHFF+fk+6Jcdtll6fTTT8/nR9J80003zSvV77rrropznn766bTjjjum3r17p2WWWSYdccQReXV7OO+889KRRx6ZV9PTNEm2AwAAAAAAACxCJMeHDBlS5ViPHj3SVlttle6///5Fvi9Kx9e2D3uHDh0qnm+55ZbpgQceSK+99lqaO3duTuzvscceacqUKenOO+9Mxx133FL+NixNku0AAAAAAAAAizBx4sS88ry62Gc9XquLKBF/zz33pHPOOScNGzas4vh3vvOddPbZZ+cE+5prrplmzZqVRo0alc4///y8V/uyyy67VL8LS5dkOwAAAAAAAMAiRAK8a9euNY5369Yt78W+OAcffHDq0qVLfgwePDjttNNOafXVV69yzkEHHZT3aP/ggw/SNddck2bMmJFX0x9zzDF5f/d11lknr6Q//PDDc9KepkOyHQAAAAAAAGAx5eCnTZtW43gc69Sp02Lfe9111+Xz5s+fn/773/+mli1bpn79+uXnixKr2iPR/uqrr6bjjz8+7w8fyfi33347nXLKKUvlO7F0SLYDAAAAAAAALEKUkH/zzTdrHJ80aVLq06dPna+zyiqrpMsuuyx99NFHacKECbWe8/7776e77747l5CP1e0HHnhg2nzzzfMq+jPPPDONHTv2G30Xli7JdgAAAAAAAIBF2HXXXdPtt99e5djUqVPTM888kwYOHFhxbOHChUu8VpSIj9LznTt3rvX1X//61+nYY49NHTp0SGVlZXklfLlWrVpVeU7j878GAAAAAAAAwCJE8vuxxx5Lo0ePzgn1KVOmpCFDhqRhw4al5ZZbLp/z9NNPp2WXXTa98847Fe/7xS9+kS699NL02Wef5edvvPFG2n333dNee+2V1lxz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AFAgyXYAAAAAAAAAKJBkO1Cr//znP+ndd99t7GYAAEuJ2A4AxUHMBoDSIrZDaZNsB7JZs2albt26pWeffTY//+1vf5tOOumkOr33O9/5Tjr11FNTQzj44IPTscce2yCfBQDFTGwHgOIgZgNAaRHboXmRbIdmrKysrOLndu3apc8//zy1bPm/Pwtt27bNx5bk8ccfT08++WQaN25cmj9//tdqx4UXXpg/r3Pnzmn55ZdPXbp0yY+OHTum9u3bp9dee63i3BYtWqQOHTrUep0HH3wwXXnllYv8nLlz56ajjjoqvfjii1+rnQDQ1IntAFAcxGwAKC1iOzRfku3QTESZmpVXXjmXrCl34403pi233LIisFbWqlWrJV7zgw8+yLPfYqbdjBkz0qGHHpoWLlxYcNtOOOGEHJynT5+erxnXeuGFF9LMmTPTtGnT0rrrrluntj3xxBPppptuWuTnRCcjOggff/xxwW0EgKZGbBfbASgOYraYDUBpEdvFdqhMsh2aiTZt2uTgWjl4LrPMMmnOnDn55/JZdnV133335c7Dtttum84666z017/+NT388MNpwIAB6fnnny/oWtH5KO+A/Otf/8qzAKOjEseijXXtnMTxeG90Gmp7RAcjvmeh3xUAmiKxXWwHoDiI2WI2AKVFbBfboTL/FUAzUR70YlbbV199lb788sv8c+VgWjnQVg+6YcKECXl/ma233joNGTIkHX/88Wn06NH5tbXXXjsH/pVWWil3DNZYY430k5/8JL+nENdee21aZZVV0jXXXFNxbNddd60oexOz6RbVAWjdunX6xz/+kbp27VrxiL1xlltuufzeFVZYIc8GrO27AUCxEdvFdgCKg5gtZgNQWsR2sR0qk2yHZtYBWH/99XNQjOB4yCGHVJl5tqify915553phhtuSLvsskv697//nUvShN/97ndp7NixOcDefPPNuYzOcccdl7p3757WW2+9OrfxscceS/fcc0969NFH0/jx49O9996bj9911115ttwnn3yS9txzz0XOlovAHt8vOjgLFizIM+8i4MfPscfNvHnzauyfAwDFSmwX2wEoDmK2mA1AaRHbxXaoTLIdmonyGWpvvPFG3qdl9uzZeWZb5ZlnlQNrbTPaRo4cmf75z3/mfWNiVl25O+64Ix8vt9pqq+XOQczMq+vMtgcffDANHjw4dzBi5t4f/vCHPKMv/o2yPHW5TgT6aHc8FtdJiPMAoNiJ7f8jtgPQ1InZ/yNmA1AqxPb/Edvhf1r/v3+BZigCa+WZZxE0+/btW/F86NChFT/HbLXYc6Zdu3b5fZXFNRYVoL/44ou8F0yUnanNlClT0vDhw9P999+fbr311vS9732vopxNzLbbf//904svvpguu+yyis9alAjsUa4nZuXF50VHINoVs+/KHzoAAJQysR0AioOYDQClRWyH5kuyHZqJ2oJeBMgo/VIufn766afT5ptvns4555z0zjvvVLwWAXq33XbLnYQI6PGIn+MR73vllVfyzLjyPWrKOwzxb1xzq622qrVdXbp0SRtuuGG64IIL0sorr1zltR122CHPDoygXm5JHYBJkyblEjvlHYDK713c7wIAio3YvvjfBQA0FWL24n8XAFBsxPbF/y6guZFsh2aiPOjF7LcIyhGoZ86cmf+tHFzjEcGz+uy5QYMG5cBefabdkixuJl7o0KFDOvnkkxf7ejzKDRs2LC277LK1nnv66aen0047rWJmX3QG1llnndyJ+Pa3v13x/RZV9gYAionYLrYDUBzEbDEbgNIitovtUJlkOzSzDsD6669f5XgEyHIRHMs7BOXBslz5/iwhOgK33HJLGjt2bJowYUL6/PPPc9Dt2rVr2mCDDdLuu++e9tprrzrv/1Ju2rRp6eKLL04PPPBA+u9//1ulLZ06dUobbbRR+tnPfpZnA9am+t435Z2Vtm3b5nYU0hYAaOrEdrEdgOIgZovZAJQWsV1sh8ok26GZiLIxH374YUUgjBln8W/l/V2qdwAqz8QrN3369NSvX78ckI877ri0/fbbp+WWWy5fKwL4U089la666qp07rnnpocffjj16NGjzm2MPWS23nrrdPPNN6c111yzSsCOTkZcb7/99kuXXnppGjJkyBKvV162R+AHoBSJ7QBQHMRsACgtYjtQmWQ7NBMxEy32V1mc6h2AefPm1Tjnj3/8Y+4EPP/88zXK3MRsu1122SU/Yt+YSy65JHcE6mLGjBn5mg899FDq3Llzjdfj2jGD7/HHH8+z8Sp3AKKETZTriVl10aGJmYXxPd566638+muvvZbL+ESHoHyfmyjxE+cNGDCgTu0DgKZGbBfbASgOYraYDUBpEdvFdqhMsh1YZAegvBxOZTFLr3LJm0Xp0qVLmj17dp0/O/aG2XbbbdOPf/zjdNJJJ6VNNtmkyn4xU6dOzZ2DW2+9NV122WVV3rv//vunZ555Jv8cHYBlllkm/xttjZmAMUOvvFRPfKfyx2qrrZY7DwBQqsR2ACgOYjYAlBaxHZqPFmV1+S8ZaBai9E3MaotZayNHjkwvvvhiuu+++6qcEzPtvvOd76T27dunI488Mpei6d69ew64MaPtzTffTLfddlu6/fbbc5mbyvvULEm8/7e//W26995707///e88Iy5m9JUH8ugUxD4yO+20U42ZejGbsF27dvlcAOB/xHYAKA5iNgCUFrEdmg/JdqBgc+fOzSVu/vrXv6aXXnopffrpp2nOnDmpY8eOae211877wRxzzDF57xoAoOkT2wGgOIjZAFBaxHYofpLtAAAAAAAAAFAgNSAAAAAAAAAAoECS7QAAAAAAAABQIMl2AAAAAAAAACiQZDsAAAAAAAAAFEiyHQAAAAAAAAAKJNkOAAAAAAAAAAWSbAcAAAAAAACAAkm2AwAAAAAAAECBJNsBAAAAAAAAIBXm/wM14QBhIBsGjwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "num_malls = len(malls)\n", + "fig, axes = plt.subplots(1, num_malls, figsize=(5 * num_malls, 5), constrained_layout=True)\n", + "\n", + "for i, mall in enumerate(malls):\n", + " mall_df = total_df[total_df[\"idx\"].str.contains(mall)]\n", + " \n", + " if mall_df.empty:\n", + " continue\n", + "\n", + " ratio_df = mall_df[\"๋ฐฐ์†ก ์ •๋ณด\"].value_counts(normalize=True) * 100\n", + "\n", + " palette = sns.color_palette(\"pastel\", n_colors=ratio_df.index.nunique())\n", + " sns.barplot(ax=axes[i], x=ratio_df.index, y=ratio_df.values, palette=palette, hue=ratio_df.index, legend=False)\n", + "\n", + " axes[i].set_title(f\"{mall}\", fontsize=14)\n", + " axes[i].set_xlabel(\"๋ฐฐ์†ก ์ •๋ณด\", fontsize=12)\n", + " axes[i].set_ylabel(\"๋น„์œจ (%)\", fontsize=12)\n", + " # axes[i].set_xticklabels(ratio_df.index, rotation=45) # X์ถ• ๋ ˆ์ด๋ธ” ํšŒ์ „\n", + "\n", + " # ๊ฐ’ ํ‘œ์‹œ\n", + " for j, v in enumerate(ratio_df.values):\n", + " axes[i].text(j, v + 1, f\"{v:.1f}%\", ha=\"center\", fontsize=10)\n", + "\n", + "# ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ถœ๋ ฅ\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "itsmenlp", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/eda/eda2_visualize.ipynb b/eda/eda2_visualize.ipynb new file mode 100644 index 0000000..0be55ad --- /dev/null +++ b/eda/eda2_visualize.ipynb @@ -0,0 +1,1466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๋นˆ ์นธ ์ฑ„์šฐ๊ธฐ(์‹คํ–‰ X)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "# import pandas as pd\n", + "\n", + "# emart_df = pd.read_csv(\"eda_final_emartmall.csv\")\n", + "# emart_df = emart_df.drop(columns=[\"ID\", \"์นดํ…Œ๊ณ ๋ฆฌ\", \"์ƒํ’ˆ ์ƒ์„ธ URL\", \"์ด๋ฏธ์ง€ URL\", \"์ •์€ ๋น„๊ณ \", \"์„ ์›… ๋น„๊ณ - ์„ฑ๋ถ„\", \"๋ฏผ์ง€ ๋น„๊ณ \", \"์„ ์›… ๋น„๊ณ - ์˜์–‘\", \"์ˆœ์„œ ์œ ์ง€ ๋น„๊ณ \"])\n", + "\n", + "# # footer ์ด๋ฏธ์ง€ ์ œ๊ฑฐ\n", + "# emart_df[\"product\"] = emart_df[\"img-ID\"].str.extract(r\"emart-(\\d+)-\")[0].astype(int)\n", + "# emart_df[\"image\"] = emart_df[\"img-ID\"].str.extract(r\"emart-\\d+-(\\d+)\")[0].astype(int)\n", + "# last_images = emart_df.groupby(\"product\")[\"image\"].transform(max) == emart_df[\"image\"]\n", + "# emart_df = emart_df[~last_images]\n", + "\n", + "# ##### ๋นˆ์นธ ์ฑ„์šฐ๊ธฐ\n", + "# # ๊ฐœ๋ณ„ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€, ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ O๋ผ๋ฉด OCR O, ์ƒํ’ˆ ์„ค๋ช… X\n", + "# ocr_description = (\n", + "# (emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"] == \"๊ฐœ๋ณ„\") &\n", + "# ((emart_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\") | (emart_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\"))\n", + "# )\n", + "# emart_df.loc[ocr_description, \"OCR ํ•„์š” ์—ฌ๋ถ€\"] = \"O\"\n", + "# emart_df.loc[ocr_description, \"์ƒํ’ˆ ์„ค๋ช…\"] = \"X\"\n", + "\n", + "# curr_id = \"\"\n", + "# for idx, row in emart_df.iterrows():\n", + "# if row[\"์ „์ฒด/๊ฐœ๋ณ„\"] == \"์ „์ฒด\":\n", + "# curr_id = row[\"img-ID\"]\n", + "# continue\n", + "\n", + "# # ํฌ๋กญ์ด ํ•„์š”ํ•œ ์ด๋ฏธ์ง€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํ’ˆ์˜ ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€ O\n", + "# if row[\"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"] == \"O\":\n", + "# emart_df.loc[emart_df[\"img-ID\"] == curr_id, \"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"] = \"O\"\n", + "\n", + "# # ํฌ๊ธฐ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํ’ˆ์˜ ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€ O\n", + "# if row[\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"] == \"O\":\n", + "# emart_df.loc[emart_df[\"img-ID\"] == curr_id, \"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"] = \"O\"\n", + "\n", + "# # ๋ณด๊ด€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํ’ˆ์˜ ๋ณด๊ด€ ์ •๋ณด O\n", + "# if row[\"๋ณด๊ด€ ์ •๋ณด\"] != \"์—†์Œ\":\n", + "# emart_df.loc[emart_df[\"img-ID\"] == curr_id, \"๋ณด๊ด€ ์ •๋ณด\"] = \"O\"\n", + "\n", + "# # OCR ํ•„์š” ์—ฌ๋ถ€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํ’ˆ์˜ OCR ํ•„์š” ์—ฌ๋ถ€ O\n", + "# if row[\"OCR ํ•„์š” ์—ฌ๋ถ€\"] == \"O\":\n", + "# emart_df.loc[emart_df[\"img-ID\"] == curr_id, \"OCR ํ•„์š” ์—ฌ๋ถ€\"] = \"O\"\n", + " \n", + "# # ์ƒํ’ˆ ์„ค๋ช…์„ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํ’ˆ์˜ ์ƒํ’ˆ ์„ค๋ช… O\n", + "# if row[\"์ƒํ’ˆ ์„ค๋ช…\"] == \"O\":\n", + "# emart_df.loc[emart_df[\"img-ID\"] == curr_id, \"์ƒํ’ˆ ์„ค๋ช…\"] = \"O\"\n", + "\n", + "# emart_df.loc[emart_df[\"์ƒํ’ˆ ์„ค๋ช…\"] != \"O\", \"์ƒํ’ˆ ์„ค๋ช…\"] = \"X\"\n", + "# emart_df.loc[(emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (emart_df[\"๋ณด๊ด€ ์ •๋ณด\"] != \"O\"), \"๋ณด๊ด€ ์ •๋ณด\"] = \"X\"\n", + "\n", + "# emart_df.loc[emart_df[\"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"] != \"O\", \"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"] = \"X\" # ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€๊ฐ€ ๋นˆ์นธ์ด๋ผ๋ฉด X\n", + "# emart_df.loc[emart_df[\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"] != \"O\", \"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"] = \"X\" # ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€๊ฐ€ ๋นˆ์นธ์ด๋ผ๋ฉด X\n", + "# emart_df.loc[(emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"] == \"๊ฐœ๋ณ„\") & (emart_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] != \"O\"), \"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] = \"X\"\n", + "# emart_df.loc[(emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"] == \"๊ฐœ๋ณ„\") & (emart_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] != \"O\"), \"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] = \"X\"\n", + "\n", + "# emart_df.to_csv(\"eda_final_emartmall_full.csv\", index=False)\n", + "# emart_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์ด๋งˆํŠธ๋ชฐ EDA" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "์ด ์ƒํ’ˆ ๊ฐœ์ˆ˜: 389, ์ด ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜: 1656\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
img-ID์ƒํ’ˆ๋ช…์ „์ฒด/๊ฐœ๋ณ„์ˆœ์„œ ์œ ์ง€์ธ๋„ค์ผ ๋Œ€ํ‘œ์„ฑ์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€OCR ํ•„์š” ์—ฌ๋ถ€์ƒํ’ˆ ์„ค๋ช…...์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€์˜์–‘ ์ •๋ณด ์–‘์‹์˜์–‘ ์„ ๋ช…์˜์–‘ ๋…ธ์ด์ฆˆproductimage์ˆœ์„œ ์œ ์ง€ ๋น„๊ณ ์ƒํ’ˆ ์ƒ์„ธ URL์ด๋ฏธ์ง€ URL
0emart-1-0์ƒค์ธ๋จธ์Šค์ผ“ 650g/ํŒฉ์ „์ฒดXO๋‹จ์ผ์—†์ŒXOX...NaNNaNNaNNaNNaN10์„ฑ๋ถ„ 1 - ์ƒํ’ˆ 2https://shopping.naver.com/window-products/ema...https://shop-phinf.pstatic.net/20240927_190/17...
1emart-1-1NaN๊ฐœ๋ณ„XNaNNaNNaNXXX...์—†์ŒXNaNNaN์—†์Œ11NaNNaNhttps://salln-static.ssgcdn.com/ui/ssg/img/pro...
2emart-1-2NaN๊ฐœ๋ณ„XNaNNaNNaNXOX...์—†์ŒXNaNNaN์—†์Œ12NaNNaNhttps://salln-item.ssgcdn.com/42/28/82/qlty/10...
3emart-1-3NaN๊ฐœ๋ณ„XNaNNaNNaNXXX...์—†์ŒXNaNNaN์—†์Œ13NaNNaNhttps://salln-item.ssgcdn.com/42/28/82/item/10...
4emart-1-4NaN๊ฐœ๋ณ„XNaNNaNNaNXXX...์—†์ŒXNaNNaN์—†์Œ14NaNNaNhttps://salln-item.ssgcdn.com/42/28/82/item/10...
\n", + "

5 rows ร— 26 columns

\n", + "
" + ], + "text/plain": [ + " img-ID ์ƒํ’ˆ๋ช… ์ „์ฒด/๊ฐœ๋ณ„ ์ˆœ์„œ ์œ ์ง€ ์ธ๋„ค์ผ ๋Œ€ํ‘œ์„ฑ ์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜ ์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜ ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€ \\\n", + "0 emart-1-0 ์ƒค์ธ๋จธ์Šค์ผ“ 650g/ํŒฉ ์ „์ฒด X O ๋‹จ์ผ ์—†์Œ X \n", + "1 emart-1-1 NaN ๊ฐœ๋ณ„ X NaN NaN NaN X \n", + "2 emart-1-2 NaN ๊ฐœ๋ณ„ X NaN NaN NaN X \n", + "3 emart-1-3 NaN ๊ฐœ๋ณ„ X NaN NaN NaN X \n", + "4 emart-1-4 NaN ๊ฐœ๋ณ„ X NaN NaN NaN X \n", + "\n", + " OCR ํ•„์š” ์—ฌ๋ถ€ ์ƒํ’ˆ ์„ค๋ช… ... ์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€ ์˜์–‘ ์ •๋ณด ์–‘์‹ ์˜์–‘ ์„ ๋ช… ์˜์–‘ ๋…ธ์ด์ฆˆ product image \\\n", + "0 O X ... NaN NaN NaN NaN NaN 1 0 \n", + "1 X X ... ์—†์Œ X NaN NaN ์—†์Œ 1 1 \n", + "2 O X ... ์—†์Œ X NaN NaN ์—†์Œ 1 2 \n", + "3 X X ... ์—†์Œ X NaN NaN ์—†์Œ 1 3 \n", + "4 X X ... ์—†์Œ X NaN NaN ์—†์Œ 1 4 \n", + "\n", + " ์ˆœ์„œ ์œ ์ง€ ๋น„๊ณ  ์ƒํ’ˆ ์ƒ์„ธ URL \\\n", + "0 ์„ฑ๋ถ„ 1 - ์ƒํ’ˆ 2 https://shopping.naver.com/window-products/ema... \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 NaN NaN \n", + "\n", + " ์ด๋ฏธ์ง€ URL \n", + "0 https://shop-phinf.pstatic.net/20240927_190/17... \n", + "1 https://salln-static.ssgcdn.com/ui/ssg/img/pro... \n", + "2 https://salln-item.ssgcdn.com/42/28/82/qlty/10... \n", + "3 https://salln-item.ssgcdn.com/42/28/82/item/10... \n", + "4 https://salln-item.ssgcdn.com/42/28/82/item/10... \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "from matplotlib import rc\n", + "import matplotlib.pyplot as plt\n", + "\n", + "rc(\"font\", family=\"AppleGothic\")\n", + "plt.rcParams[\"axes.unicode_minus\"] = False\n", + "seaborn_color = sns.color_palette(\"pastel\") # Set2, pastel, husl\n", + "\n", + "emart_df = pd.read_csv(\"eda_final_emartmall_full.csv\", encoding=\"cp949\")\n", + "\n", + "product_len = len(emart_df[emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"])\n", + "image_len = len(emart_df[emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\"])\n", + "print(f\"์ด ์ƒํ’ˆ ๊ฐœ์ˆ˜: {product_len}, ์ด ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜: {image_len}\")\n", + "emart_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ๋ฉ”ํƒ€\n", + "### ์ธ๋„ค์ผ ๋Œ€ํ‘œ์„ฑ: O, X\n", + "### ์˜์–‘ ์ •๋ณด ๊ฐœ์ˆ˜/์„ฑ๋ถ„ ์ •๋ณด ๊ฐœ์ˆ˜: ๋‹จ์ผ, ๊ฐ™์€/์œ ์‚ฌํ•œ ๋‚ด์šฉ, ๋‹ค๋ฅธ ์ •๋ณด ์—ฌ๋Ÿฌ ๊ฐœ, ์—†์Œ" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "์ˆœ์„œ๊ฐ€ ์œ ์ง€๋˜๋Š” ์ƒํ’ˆ๋“ค์˜ ์ด ์ด๋ฏธ์ง€ ์ˆ˜: 1351\n" + ] + }, + { + "data": { + "image/png": "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nM61p/U7nChHxqoLbOca4Jycdk7EqiCJVf4+b2T2s0kmPldxDXBOTjsnYlWQxKo0zscfrgHOKSeeU2QGY1VAC537o0t76rCv9Hz33XdSt25d9/etW7eWKVOmeG2jw8502OZVV12VbccKIOciVgFwAmIVACcgVgE5V0CTUm3atJEZM2ZIQkKCGVa2aNEi6dq1qwwePNg8r5nw+++/X9auXWuGjOmcxT59+siGDRukR48e7v0MGDBAxo8fL3PmzDHf//nnn2YZUJ2bHEp3EgAEBrEKgBMQqwA4AbEKQNAkpXRFhQ8//NAU7NLiXBpYdNUFa/7vFVdcYYZjPvzww2ZpTy2adezYMVm2bJkp2mWpVKmSzJo1yxSt0+20CJ4GrE6dOgXw7ACECmIVACcgVgFwAmIVgKAsdB4MtBCXDhu1q2jgJyudv3KGr44N/12xAgjktRXqeD2B7MG1FRyvp52fj/jcAiciVmUtXk8gsNdW0NWUAgAAAAAAQOgjKQUAAAAAAADbkZQCAAAAAACA7UhKAQAAAAAAwHYkpQAAAAAAAGA7klIAAAAAAACwHUkpAAAAAAAA2I6kFAAgW/z000/Svn17KV68uBQoUEAaNWokixcv9trmzz//lG7duknlypUlNjZW6tSpIxMnTvTaZs6cOdK6dWspUqSIFCxYUJo1aya//fabzWcDAAAAIKuRlAIAZIvevXtLixYtZNu2bXL48GF55plnpF27drJ582b3Nq+99prUrFlTli1bJseOHZMxY8aY7aZPn26eT0hIkKeffloefvhh+eeff2Tfvn1y1113ya233ipHjhwJ4NkBAAAAuFiRF70HAAD80FFR+fPnd39/5513yvz582XevHlSpUoV0/b+++9LRESEexsdTdWnTx+TlLrjjjskKipKVq9eLfny5XNvoyOrZsyYYUZitWnTxuazAgAAAJBVGCkFAMgWngkpS3x8vERHR7u/90xIWfbv32+m+6nw8HCvhFRa+wEAAADgPIyUAgBku0OHDsmnn35qRj2NHj063dFVH3zwgSxfvjzVcy6Xy0zhe+eddyQsLEyaNm2azUcNAAAAIDuRlAIAZJuqVauaRNKpU6ckT548MmLECPOvP++9954MHTpUvvzyS/NzljNnzphi6cnJyWY/hQsXNokpHUUFAAAAwLlISgEAso2urqc0obRx40Z54okn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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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cePspJNOsp49e5Z6rXpDeUG6SLTdOt6ql4JzVfF9AQA4sAhKAUA18uc//9kljdYdYw2LUSBFvRRCeReBkS50vaTFGtqmiykNl9LFjO42eyp78T9nzhy3Xl1UnHjiiW5IyrnnnuuGPGkbdHGgoRnl9bhQ0EfBmuCLsdBlDvQMdbrwVd6rU045JeIyCippuKOGlTz//PMuGPh///d/duONN9pNN93kltGFkO7Sh/r3v//tAnOhw7t++9vflulBojqHSzReHgUldE4oYKJeBBridNxxx7neDF6QQr0nIu13XVyqF4ku8BXg9I6T6qIeLBr66AWMgi9mFbRQfi31DlFwTT12FHTU6zVUSME6LxCgdUeidaoXmZbVa70giPaXem7pnNT+V8CvsheY6tmkeihYoMCALoLnzZvneuVE837RsdbwVOUD0nmnHhm6mNb2afiSfmqIqPaPeul4PWaCab9rKJd67Hm9P/TQ78EBPK1fF9HhhuVqP4QL7Kgs+HypbK8QvVbnoXK1KUeP3gMKDikYE/z/dCwive+83kXher5421deUEr1f+2119znRygNKdTx13s0eBIB9YhR4ESBqeDzOlLgL9zQSp3rocEZBbu03li+/3QeKJijz04vEBVM7682bdrs1+eeevQpsOkJDjKG22c6txUYUk88vffC9TZVDzadM1q3gtfqNRkNHUfdFHnhhRfcEDx9Tuj/qd56Tu8v9a7Ufoz0ftd3jPJRadipAqd6fygoppsECibqs0j1UkCTWRUBoBrwAwCqheeff96fkZHhf+edd9zfa9as8Tdp0sR/6623+ktKSgLLdejQwZ+amupv1KiR/+qrry6znlWrVvnT09P9KSkpbp2LFy/W1UngMXbsWLdc165d/S+99FJU2zZz5kx//fr13U958803/XXq1PE/88wzpZYbNGiQ/+677w67DpXrf5bH5/P533777ai2KS8vr9R+iUR1bNOmjb+goMCfm5vr3717d5n9dcghh/j//ve/u7/1fJcuXVxdtHzoekKde+657hiF+uKLL1x9tJ2ea665xv/b3/7WHy0dvwYNGvj/+9//ur8ff/xxf7169fz//ve/Sy134okn+l944YUyr9fx0vILFiwIlK1cudJ/6KGH+p977jl/UVGRK9PPtLQ0//Lly0u9XuWtW7f2P/jgg4F9UVxc7J81a5a/efPm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AIBqhjYUAADAfgaltmzZ4u7olZSUuIemMZ4wYYLLjeD3+12ZfuqRk5NDgwoAAIA2FAAAwP4HpUaPHl2mbObMmXbPPfdE83IAAICkRBsKAABgP4NSt956q2VkZFha2k+L667ehg0b7I477rDU1NRSyw4fPtzq168fzWoBAABqNNpQAAAA+xmUOv74413Xc3U597qe/+1vf3M/va7nXvfz4NwIAAAAyYw2FAAAwH4Gpfr37x/NYgAAAAhCGwoAAGA/g1IydOhQKygosNNOO8369etnDRs2jPalAAAASYs2FAAAQHgpFqWFCxfab37zG1u2bJn16tXLrr/+etu+fXu0LwcAAEhKtKEAAAD2MyiVnp7upin+85//bIsXL7ZOnTrZiSeeaJ999lm0qwAAAEg6tKEAAAD2MyilJJ0ezRZz9dVX27Rp02zw4MG2ZMmSaFcDAACQVGhDAQAA7GdQKjc3t0xZhw4d7MUXX7QLL7zQdu3aFe2qAAAAkgZtKAAAgP0MSo0ePTps+bHHHusSeJIbAQAAoCzaUAAAAPs5+965554b8blhw4ZFuxoAAICkQhsKAABgP3tKAQAAAAAAAAcKQSkAAAAAAADEHEEpAAAAAAAAxBxBKQAAAAAAAMQcQSkAAAAAAABUn6CU3++344477sBuDQAAQA1HGwoAAKASQamnnnqq1N9PPPGE+Xw+KygoiOblAAAASYk2FAAAwH4GpR599NFSfz/55JPuZ926dd3Pk08+2erUqWOZmZmWlZVl69ati2a1AAAANRptKAAAgP0MSqmRtHbtWnvrrbds9+7dVrt2bVeekZHhfhYWFtrKlSttw4YNduSRR1rLli2jWS0AAECNRhsKAABgP4NSakD9+OOPNn78eOvSpYulpqa68lq1armf+rtZs2bWqFEjd7dP3dIBAACSXazaUE2bNrXNmzeXKddwwbZt21p2dradcsoptnjx4jLLqHdW//79rX79+taiRQsbM2aMlZSU7NN2AAAAHPCgVHp6unXv3t2mTZvm7uZ5Xc537dplM2fOtJycnMCyXmMLAAAg2VV1G0q9rx566CHbtGlTmecUCJswYYK99957tmPHDrvmmmvs7LPPth9++KHU63v37m19+/a1LVu22IIFC2zu3LkuMAUAAJAQQanQRpLu5Ml3331njz/+uGvEeOglBQAAUPVtKL2+SZMm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W+O9aUBCoA0F2lDJjfYTIqENVbUIStWwD1KvoTRt2jT7+9//7iL60rZtWzv55JPt+++/txkzZrgyPkBrHh1T7xz497//bX369LEHHnjAGjdubL1797YpU6ZY/fr17eyzz7avv/7adT1GzeOdA//617/csf7444/d72vXrrUzzjjDmjdvbg899JB98cUXgaEpwt2+mun999+3U0891VatWuW+G0aPHm3NmjWzgQMH2rx582z9+vXx3kQg7mhDgTYUaD8hFG2o2PD56YNco3z++ed2//33u4Scv/jFL+zxxx+3c845x0X5f/zxR/vnP/9pK1assIcfftgyMzPjvbmoAosXL3Z3drZt22b9+/d3jahnnnnG6tSp484N3fX98ssvXX4EPa/ux7oDiJpDd+/UvXj79u128803W69evdxxVmNL54C+WNXYatmypT311FM2atQoa9Omjbvzo0Y5jauaIzc312644QZ3p//nP/95qef0/aDPCR1/+eijj1yD+7DDDovT1gLxRRsKtKGSG+0nBKMNFTu8c2oQzQaiWUHOPfdcmzp1qv3+97+3SZMmuYR8SsimnAjqgq5ux7oDhJpH+S6uvvpqO/HEE905cOmll9qRRx7pvlzVaFIjW43qY4891l555RUrKCigC3oNpLwH6lquu3tqUEnfvn3dRZQaXPrC/M1vfmOHHnqo+/2uu+6yl19+2d3tYYrjmsE7hvpM0ExBXbp0CTyni+srr7zSZs2aZb/97W9d13P9rSSuWhZIRrShQBsKtJ8gtKFij6BUNaY3RbD//ve/buz7oEGDAmXqZqwu51438+OOO8527dplH374oeuGLnyA1hzt27e3OXPmuA9HKSoqsgULFrgGle7y6ENVDW3d8evYsaMbF60ZROh6WvN0797d/fQSMK5Zs8YdZzW45NZbb7VPPvnE5s6dax06dLABAwbYjTfeGNdtxv7TcKPVq1cHhiDookmJmjXc4PXXX3d3c9Xzo2vXrq4HgIYinXXWWe7CS6/THWAgGdCGQijaUBDaT8mLNlT8EJSqpu644w7XlVC8xpI+PI844gjXrVjefvttu/DCC904WN3Z09/qaqwx0JpNRN1OhYSdNYcaSpoVROeEjrG+QHXHz4vc16tXz+VIWLhwoWto6YNVx////u//4r3pqCQ1kqLhvb8PP/xwq1Wrljsv1NDWxZdm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c+9n8CwuKmvfvr01a9bMPvzww6jWp3Nl5cqVtnPnTnfuAACQDGhDJRfaTwAqQlAKqITQ6WSVWPPVV1+1c889t8I7fcHWrVtnrVq1qqKtRFUe/2+++cY6derk/tbHp3JXaDriyy67zA0ZUGJNPSp7t46pigEANRltqORF+wlAecgpBUTh448/dl2FvS+9iRMnuq7hGzZssLFjx7o7dpqOuKK8CF4M2GtM6YsU1cdDDz1kp59+uvtdd2uV50J36zQdtRpXOi90x3f79u2V7j5OgwoAUBPRhgLtJwDlSSv3WQC2du1adwenY8eOrgF0yy23uMSc999/v/3iF79wy2jml1deecUla1SizUhCv2j5Ik1c3333nTVv3rzUHbihQ4e6hlOTJk3sqKOOskceecTOPPNM99x//vMfu/vuu11DKz8/n7wGAICkRxsq+dB+AlBZ9JQCguTl5blkmsF35DTVrHIWzJ4923r37m2/+c1v3DSzakxt2bLFLr/8cpfn4OKLL3aNKaYgrv7UxVyNI2/2Hu9ubJ06dewvf/mLu6urpJxqUKnxpXPgoosusiuuuMLNBnTwwQcHGlQbN250jSwAAGoy2lCg/QRgXxCUAv5HX3y6m/fkk0/ajz/+GEjGKH369LGePXvaBRdcYFdddZUr06wxnTt3ttq1a9uyZcvswgsvdOVK0qlZZXTnR0jbVn1oKIFoemEdz1tvvdX9HZx41TsXdB6oO/opp5xiCxYssP79+9ugQYNKre+6666zXr162fr162NcEwAAYoc2VHKj/QRgfxCUQtKbM2eOff/99+4OXY8ePdy0srNmzXLP6S6PGkQNGzZ0Y+HVwNIXp2b7+OCDD9yX7a9+9SurVatWYH3qnqyuyU899ZS740cX5MSnnAbdunVz00sXFha6MjWYdGf3q6++KtW4lnHjxrn8F++++66bLeb55593y7z88suBc+Cwww6zb7/91q27Xbt2casbAABVhTZUcqP9BOCA0Ox7QDL69ttv/YMGDfKfccYZ/i+++CJQPnr0aP91113nX7Nmjfu7qKjI/czLy/Pfeeed/t69e/vfeOMNV/b000/7Tz75ZPf7okWL/Keeeqq/U6dOgeeR2JYuXeq/8sor/d26dfPPmTMnUL548WL/b37zG//hhx/uP//888O+du3ataX+fuyxx/x9+/b1H3vssf4jjjjC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "meta_df = emart_df[emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"][[\"์ธ๋„ค์ผ ๋Œ€ํ‘œ์„ฑ\", \"์ˆœ์„œ ์œ ์ง€\", \"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\", \"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\"]]\n", + "\n", + "len_ordered_img = len(emart_df[(emart_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (emart_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")])\n", + "print(f\"์ˆœ์„œ๊ฐ€ ์œ ์ง€๋˜๋Š” ์ƒํ’ˆ๋“ค์˜ ์ด ์ด๋ฏธ์ง€ ์ˆ˜: {len_ordered_img}\")\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "for idx, col in enumerate(meta_df.columns):\n", + " plt.subplot(1, 4, idx+1)\n", + " bars = meta_df[col].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "\n", + " cnt = 0\n", + " for bar in bars.patches:\n", + " cnt += bar.get_height()\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + " \n", + " if idx >= 2:\n", + " plt.xticks(rotation=30, ha=\"right\")\n", + " else:\n", + " plt.xticks(rotation=0, ha=\"center\")\n", + " plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + " plt.ylim([0, 400])\n", + " plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.suptitle(\"์ƒํ’ˆ๋“ค์— ๋Œ€ํ•œ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ\")\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "for idx, col in enumerate([\"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\", \"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\"]):\n", + " plt.subplot(1, 2, idx+1)\n", + " bars = meta_df[meta_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\"][col].value_counts().reindex([\"๋‹จ์ผ\", \"๊ฐ™์€/์œ ์‚ฌํ•œ ์ •๋ณด ์—ฌ๋Ÿฌ ๊ฐœ\", \"๋‹ค๋ฅธ ์ •๋ณด ์—ฌ๋Ÿฌ ๊ฐœ\", \"์—†์Œ\"]).plot(kind=\"bar\", color=seaborn_color)\n", + " \n", + " for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + " \n", + " plt.xticks(rotation=30, ha=\"right\")\n", + " plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + " plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.suptitle(\"์ƒ์„ธ ์ •๋ณด ๊ตฌ์„ฑ์ด ์ •ํ˜•ํ™”๋œ ์ƒํ’ˆ๋“ค์˜ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ๊ฐœ์ˆ˜ ์œ ํ˜•\")\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "##### ์ˆœ์„œ ์œ ์ง€ X์ธ ๊ฒฝ์šฐ, ์–ด๋–ค ๊ตฌ์„ฑ์„ ๊ฐ–๋Š”์ง€ ํ™•์ธ\n", + "# plt.figure(figsize=(12, 6))\n", + "# bars = emart_df[emart_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"X\"][\"์ˆœ์„œ ์œ ์ง€ ๋น„๊ณ \"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "\n", + "# cnt = 0\n", + "# for bar in bars.patches:\n", + "# cnt += bar.get_height()\n", + "# bars.annotate(f\"{bar.get_height()}\",\n", + "# (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + "# xytext=(0, 0),\n", + "# textcoords=\"offset points\",\n", + "# ha=\"center\",\n", + "# va=\"bottom\")\n", + "# plt.xticks(rotation=30, ha=\"right\")\n", + "# plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "# plt.ylim([0, 400])\n", + "# plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "# plt.suptitle(\"์ƒํ’ˆ๋“ค์— ๋Œ€ํ•œ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ\")\n", + "# plt.tight_layout()\n", + "\n", + "# emart_df[emart_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"X\"][\"์ˆœ์„œ ์œ ์ง€ ๋น„๊ณ \"].value_counts()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€: O, X\n", + "- ์ด๋งˆํŠธ๋ชฐ์€ ๋Œ€๋ถ€๋ถ„ X์ผ ๊ฒƒ\n", + "- ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€๊ฐ€ O๋ผ๋ฉด, ํ•ด๋‹น ์ƒํ’ˆ ์ž์ฒด๋ฅผ ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€ O๋กœ ๊ตฌ๋ถ„\n", + "- ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€ X์ธ ์ด๋ฏธ์ง€์˜ ์ˆœ์„œ ์œ ์ง€ X ๊ฒฝํ–ฅ ํ™•์ธ" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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wgn//Oc/05wbAEBpUq959aKPtW3bNrvmmmvc7xs0aGAXXHCBvfvuu5HfX3TRRa7+UP0Q3O67776o42hKiNtvv91OOukkd1OteuXTTz9NS94AAGXX3vj444/tF7/4hbVp08aV/506dbLnnnsuah/aGyWHoBSAjKHht71797b169fbzp077eabb7YBAwa4BQ+8hx9+2J544gm34IGi7q+++qrNmjXLxo0b535/8OBB+81vfuMaJJ999pn95z//scsuu8z+67/+y3bt2lWGuQMAlIQDBw7YAw88YNu3by/wO6Wde+651rx5c/u///s/F6D67W9/6+Yb9Q4fPmx//vOfoxbb0aa6I+i2226zDz74wFasWOGCX2pwKKClegYAUHHbG/fee6916NDBPdBQ/fD444+7/dTmENobJYvhewF0pwXK1v79+92ccEF6SvGtb33LfvnLX7qfzzvvPPv1r39tl1xySWQfVRD33HOPvffee+7JtiqKE044Ieo4WolTc81dfPHFacpNZqO8KxlcRyC9HnvsMbeQjcr6Q4cOuSCUekN5WhynSZMmdvfddyc8hlZ3vvHGG10DIhEFsbQitHpG6Qm4p9WfFZhSfVLZUN6VDK4jkPntDY3A0LzWQepNu3LlSvuf//kf2htJYvgegHIntoKQ3NxctxKn17BhQ1u1alXUPlp98+yzz3b/z8rKKlBBxDsOAKD8GTp0qH355ZdxeyvpabZ60d50003H/D7qhathf8GAlGjIx+zZs4/5+ACAzG1vxAakRD1vfWCF9kbJIigFICNpqMSkSZNs+fLlrhHg3Xnnne5J+bXXXusaBj/96U9dN9m77rqrwDHUEXTr1q1uJc5QKOSejgMAKqZly5bZySef7IbnXX311dasWTM75ZRT3JNvPa0Nev31112dUK9ePTdniIZlqDHhrV692tq2bVvgPVq1auV+BwCouO2NWJpz6qmnnor0pAqivXHsCEoByCinnXaaewqhyQc1n4e60x5//PGR37du3drND6KA1LPPPmuLFy92wzfWrVsX2UdDOvR0W8dRo2TKlCnuOHqqAQComD7//HMXkOrTp49rFKxZs8aWLFliGzZssCFDhkT2O+uss9zQjMmTJ7vXaLLav//97y6QFRzeUbdu3QLvoSDWvn370pYnAED62xtBehh++eWX20svveRe59HeKDk5JXgs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64k7ADObM6Gsz6D86jvWMlV5KO/UAFTDWo1GmTFjhlt1T5OTn3baaZH91ChVA3Ljxo2RRqCGAKpRFdS3b183H9XPfvYzNwn68ccfb3fffXfUPjq29tm0aVPSPaU06boawP46ZkpvlYrYA4c8lY88ffTRR5Hj01MqtTydccYZGfvZU3lXv379jK43yoPyUP8CZYI2R4VrcyRb3tFTCgBQLigQpYbTqaeeGpWungJNmza1Tz75xLp16+aCWOvWrXONuyD1PlDPAtHQvQULFhR4j+A+8SjopS2WGnXagnxDMpZvGCabHnvc4qSrgRkvPdE5pppOnshTMD343j4AE6uk0uPlszjp8Y6dKL2085Spn71ExwMA4Fgw0TkAoFzo0KGDnXTSSfb0009HpWvYjYYxadiS9OvXz6ZPnx61j4araEjR2Wef7X7WEMDXX389MieUp4nU+/fvX+p5AQAAAEBQCgBQTuhJ/iOPPGK33HKLPffcc24YnYbs/eQnP7Frr73Wzekit956qz355JM2Z84c9/PHH39sV111lRuq55/0q7fVlVde6eai0twwmmfl/vvvd3Oq6FgAAAAASh9BKQBAufGDH/zATWiuSc7r1q1r3bt3t/POO88efPDByD6tW7e2V155xU1KromQe/XqZcOGDbPBgwdHHUuv0VA99cDSkL9Fixa5Ff001xQAAACA0sfgcABARkq0Dsf5559vS5YsKfS1Wk1q8eLFhe5z3HHH2V133eU2AAAAAOlHTykAAAAAAACkHUEpAAAAAAAApB1BKQAAAAAAAKQdQSkAAAAAAACkHUEpAAAAAAAApB1BKQAAAAAAAKQdQSkAAAAAAACkHUEpAAAAABXSO++8YwMHDrTGjRtbrVq17JxzzrGFCxdG7ZOXl2e33367nXTSSVa7dm3r16+fffrppwWOtWrVKuvRo4fVrFnTTj31VHv00UfTmBMAqJgISgEAAACokEaMGGG9e/e29evX286dO+3mm2+2AQMG2Nq1ayP73HbbbfbBBx/YihUrbMeOHdazZ0+76KKL7ODBg5F9tmzZYn369HHH27t3r73xxhs2ZcoUmzp1ahnlDAAqBoJSAAAAACok9YoaMmSIVa9e3Y477ji79NJL7cc//rHNmzcvEmyaPHmy/eUvf7FGjRq5fX71q1/ZaaedZk899VTkOHfccYddfvnldskl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nj129913W7du3eyll16yU089taxPDwBQTtHmAIDKJ6mg1NixYwukvf76624IBwCgcgmusle7dm276667rF+/ftanTx9XNzRv3rxMzw8AUD7R5gCAyiepoNStt97qnowHlwDfsmWL/e53vyuwBPiIESNcIwUAUDHFWwXpu9/9rj300EN26aWX2rvvvmvHHXdcmZwbAKD8os0BAJVPUkGp73znO64rbXAJ8D/+8Y/u39glwJnwFgAqtmuuuSZu+oUXXmhvvvmmbdy4MWrVJAAAkkGbAwAqn6SCUv379y/9MwEAlAua5DwRzS8FAEBx0OYAgMon6aWStLrS4cOH3RLgmjukbt26pXtmAAAAACoV2hwAULlkJbvjihUr7Cc/+YmtWbPGunfvbr/+9a9t9+7dpXt2AAAAACoN2hwAULkkHZTSpLVadvXOO++0Dz/80Nq1a+cmtv3ggw9K9wwBAAAAVAq0OQCgckk6KKVJBz2tfnH99dfb7NmzbfDgwbZq1arSOj8AAAAAlQRtDgCoXJIOSuXm5hZIa9OmjT377LP24x//2Pbv35/ym2vljBkzZlivXr2sSZMm1rBhQzfB4ccffxy13+OPP24tW7a0mjVr2nnnneeemsTatGmTe62Whm3atKmNHz/erc4BAAAAoHwojTYHAKACBKXGjh0bN/3MM890ExIWZ6z3nj177KGHHrJRo0bZJ598Yp9++qmdc845rsvuvn373D5TpkyxqVOn2oIFC9z+N9xwg/Xu3du2bdsWOc6BAwfca/r06WM7d+605cuX2+LFi11gCgAAAED5UBptDgBA5gqF1V2pjPi3DoVCUekdOnRwwSqNH1evp3fffdeNJ/dGjBhhVapUsXvvvTeyBLkmRXzhhRci+3z++efWunVr27Bhg9WvXz+p89m7d6/raaXgV61atUool0A5N2dCWZ9B+dU3/o11Jihueffb3/7WzfeRyJEjR9ymnqpfffWVfec737ErrrjCKirqDaAghlgVn+6BMxXlXcngOgIJ0OaocG2OZMu7pHtKlQYFo2IDUmrE7Nq1y530woUL7eSTT44KSMnAgQPd2HJv1qxZNmjQoKh9GjVqZN26dbN58+aVci4AoPJQma35Po4//nirUaOGK6u1qcLREOs6deq4BwENGjSwxo0bu3QAAAAAiCfHMoh6TqkXVPv27a1Lly42adIk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qBdffNE9VV+yZIkLUGkp8alTp9qCBQvcSoDTp0+33r172/LlyyMNHjVwFMS66aabbObMmS54ddVVV7ngljYAQHrR5gCAyimp4XvxaNjGAw88ULJnAwAoF9SjKCcnx20aRuGH602YMKFU31dLhK9bt86WLVsWSfvpT39qL730ki1evNhatWplo0ePtnfffddatGjhfj9o0CB777337L777rN7773XpU2ePNn1oFLvKDnxxBPtueees9atW9vw4cOtfv36pZoPAEByaHMAQMWWVdzutaoggitgAAAqDwV1FJASzSelOaYeeuihUn/fevXquTrok08+iaRpKIdWaeratasbiqfeUe3atYt63cCBA2327NmRn7WKk4JVQZqXpFu3bm5YIACg7NHmAICKr1g9pTTRrZZqBQBUTg0aNLBbb701Ku3JJ58s9fetU6eO3XXXXda9e3f79a9/bU2aNHHzR2nI3ZlnnmmTJk2ytm3bFnidelCph5Umy1UAbfXq1Qn30+8SOXTokNu8vXv3un/VU0yb+MnfNeG7Ns+nq0eZepcVla6GmAJ+/rjBdImdSD5Ruu/NFkzXcbV/7DkmSidP5CmVPPn31rF13OCxU03XeWhLlB7MZ3HTJfZcEqWXdp78dczEz17s+6QDbQ4AqPiSCkpt3LjRatSoEamw9NRi165d7ndahenTTz+1l19+2d3g//jHPy7tcwYAlDGV/bE0/0c6qNfT3/72NzdvlIJI6jW1atUqN+fI/v37rW7dunF7WKkO01xSCmwVtt++ffsSvvfEiRPjzjm1YsUKN1m6NGzY0J2XVobSXFVes2bN3LZ27VrXu8tr2bKl66WlPASXOFdvL52rjh1sLHbs2NFd6+AQRunSpYube0W9xjw1KtWDTO+nObi8atWqWadOnWzHjh1uSKRXu3Zta9++vW3dutU2b94cSSdP5CmVPOk7pKCGgsZK9/eMPgCi89T7Bc9FZYq+f/puagteA52L9g2eo+5La9asabt3744KFOvaaPLrnTt3RgVRdGy9h1ZrCwZ2FGDX9dcCCkGaf05517X30pEnydTPnp9svDTR5gCAyicUjn2kE4fm5dCTZf+kRvyTk7PPPtvN46E5PebOnWs///nP3VYe6Ym3bmZUMfvVPoBKb07pzhFUofUdaxW1vFNjKNiA8XVFcFhdaXj99dftuuuus4cf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+j3//PNt3LhxZXr+AAAAAAAAiC+jJhWJnXP9uOOOc5OVa0tmnqnXXnutFM8OAAAAAAAAlaKnFAAAAAAAAComglIAgHLnhRdesM6dO7tlZlu3bm033XRTpLet5ha8/fbb7aSTTnK/12IYn376adxl63v06GE1a9a0U0891R599NEyyAkAAABQeRGUAgCUK/fff7/deeed9thjj9mePXvsb3/7mwssKRglt912m5t/cMWKFW4l1p49e9pFF11kBw8ejBxDC2JoIY0RI0a4RTTeeOMNmzJlilswAwAAAEB6EJQCAJQba9eutbvuusvefPNN69atW2RRjPHjx1t2drYLNk2ePNn+8pe/WKNGjdzchL/61a/stNNOs6eeeipynDvuuMMuv/xyu+SSSywUCrneVgpIjRkzxo4ePVqGOQQAAAAqD4JSAIBy48knn7QrrrjCGjduHPf3r776ql1wwQVuJdaggQMH2uzZsyM/z5o1ywYNGhS1j4YDqsfV0qVLS+nsAQAAAAQRlAIAlBvvvvuude/e3Z555hnr0qWLNWjQwM455xw3/E5Wr15tbdu2LfC6Vq1aud/JF198Ydu2bStyPwAAAAClK6eUjw8AQIn5/PPP7aGHHrImTZq4IXoKIs2ZM8cGDBhgb731lu3fv9/9Lla9evVs37597v/ap0qVKnbCCScUul88hw4dcpun+ajkyJEjbpOsrCy3aY4rP89VMF3DA/2k7IWlaziihhb64wbTJXaYYaL0nJwcd9xguo6r/WPPMVE6eSJPqeTJv7eOreMGj51qus5DW6L0YD6Lmy6x55IovbTz5K9jJn72Yt8HAICSQFAKAFBuKJh0+umnu0nJPc0LtWTJEnviiSesRo0atnv37gKvU5qG5on2OXz4sOXm5lq1atUS7hfPxIkT3fxVsTSpevXq1d3/GzZs6IJlGzZssO3bt0f2adasmds0L5YmaPdatmzp5r/SaoA6J69du3ZuGKKOHWwsduzY0V2HZcuWRZ2Deo4pXytXroykqVHZtWtX935r1qyJpCvfnTp1chPBr1+/PpKu1Qrbt29vW7dutc2bN0fSyRN5SiVPCuwqqKEAsdJ37doVFQDReer9gudStWpVFxRW0Fhb8BroXLRv8Bz1PdZ3Vd/ZYKBY10YB5507d0YFUXRsvYcC28HAjnpb6vqr92SQhggr77r2XjryJJn62Ttw4EDU8QAAKAmhcOwjnUpMT7x1M6OKuVatWmV9OkBmmDOhrM+g/Oo71jJVeS3v1CPqrLPOchOSB2k43/PPP28XX3yxLViwwGbOnBn1++eee86efvrpyDA/NSC13xlnnBG1X5s2bdx+GiKYbE+p5s2buwawv46Z0lulIvbAIU/lI08fffRR5Pj0lEotTyqTMvWzp/Kufv365a7eyDTltf4FSh1tjgrX5ki2vKOnFACgXAWlxo4dazfddJMdf/zxkXT1CNAcUX369LHRo0e7SjBY+SlI1b9//8jP/fr1s+nTp0cFpdR7QD08zj777ITvr54P2mKpUactyDckY/mGYbLpscctTroamPHSE51jqunkiTwF04Pv7QMwsUoqPV4+i5Me79iJ0ks7T5n62Ut0PAAAjgUTnQMAyg2tonfqqae6IXuffPKJG4ry7LPP2rRp02zEiBHud1deeaUNGTLEDa/R7++//343LOXaa6+NHOfWW291K/lpPir5+OOP7aqrrrK7776bhhcAAACQJgSlAADlhnoKvPLKK24uFfVoqlu3rv35z3+2N998082lIw8++KD7fYcOHdx8MYsWLXLD9oI9q1q3bu2OozmiNC9Nr169bNiwYTZ48OAyzB0AAABQufA4GABQrmgS40mTJrktnuOOO87uuusutxVGk/suXry4lM4SAAAAQFHoKQUAAAAAAIC0IygFAAAAAACAtCMoBQAAAAAAgLQjKAUAAAAAAIC0IygFAAAAAACAtCMoBQAAAAAAgLQjKAUAAAAAAIC0IygFAAAAAACAtCMoBQAAAAAAgLQjKAUAAAAAAIC0IygFAAAAAACAtCMoBQAAAAAAgLQjKAUAAAAAAIC0IygFAAAAAACAtCMoBQAAAKBSaNSoke3YsaNA+uOPP24tW7a0mjVr2nnnnWcffvhhgX02bdpk/fv3t9q1a1vTpk1t/PjxlpeXl6YzB4CKiaAUAAAAgArtwIED9sADD9j27dsL/G7KlCk2depUW7Bgge3Zs8duuOEG6927t23bti3q9T179rQ+ffrYzp07bfny5bZ48WIXmAIAFB9BKQAAAAAV1mOPPWYNGza00aNHF/jdwYMHXfozzzxjLVq0sKysLBs0aJANGDDA7rvvvsh+kydPts6dO9v1119vOTk5duKJJ9pzzz1nkyZNckEqAEDxEJQCAAAA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_df = emart_df[[\"img-ID\", \"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\", \"OCR ํ•„์š” ์—ฌ๋ถ€\", \"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\", \"์ƒํ’ˆ ์„ค๋ช…\", \"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\", \"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"]].copy()\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 3, 1)\n", + "bars = image_df[image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"][\"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ „์ฒด ์ƒํ’ˆ ๊ธฐ์ค€ ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "# ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€ O == ๊ธด ์ด๋ฏธ์ง€ 1๊ฐœ ํฌํ•จ\n", + "plt.subplot(1, 3, 2)\n", + "bars = image_df[image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\"][\"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=\"lightgray\")\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"๊ฐœ๋ณ„ ์ด๋ฏธ์ง€ ๊ธฐ์ค€ ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 3, 3)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"ํฌ๋กญ ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ํฌ๋กญ์ด ํ•„์š”ํ•œ ์ƒํ’ˆ\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### OCR ํ•„์š” ์—ฌ๋ถ€: O, X & ์ƒํ’ˆ ์„ค๋ช…: O, X\n", + "- OCR์ด ํ•„์š” ์—ฌ๋ถ€๊ฐ€ O์ผ ๋•Œ ์ƒํ’ˆ ์„ค๋ช… O์ธ์ง€ ํ™•์ธํ•ด์•ผ ํ•จ" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABL0AAAJOCAYAAABSl3UsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA0W1JREFUeJzs3QeYVNX5x/F3l967FMECiGABiWDDLhoEDFE0djCW2MWSqNFgV6ISUYMNTYhdUVQ0/kUFu6ICEhEF0QBKifTe2Z3/8zt6hjt3Z3Zn68ze/X6eZx7Ys3fv3HruOe89JScWi8UMAAAAAAAAiJDcTG8AAAAAAAAAUNYIegEAAAAAACByCHoBAAAAAAAgcgh6AQAAAAAAIHIIegEAAAAAACByCHoBAAAAAAAgcgh6AQAAAAAAIHIIelWg/Pz8hP/HYrEK+V59z/r16yvs+1JtA6qObdu2uQ+qlrK4z5cvX05+gaywadOmTG9C5G3YsIFnBUqktM8JlYt1/WVyGyp6vUB5WrVqlW3durXCrv28vDzbvHlzQv06TL/bsmULz/NKojzPE0GvYvr666+tWbNmJTopRx11lN10003u/40aNbKXX365zLbrnXfecduVrPCoSmSDBg2sdu3a1rRpU2vdurW1bdvWffT/Fi1auO2pU6eOVa9e3RYvXmxlSZlStWrVbNKkSUl/V1hmFVQVC8YrVqxw5+W7776zbHPDDTfYcccdl/R3H330kbVq1arQv+/QoYP9+9//Lqetix7dw/7evOqqq+yyyy5Lu2AfLoRcc801dtppp5X5Nv7xj3+0o48+ulTr6Ny5s40ePbrEf//6669b3bp1S13wCvvHP/7htq00eZPyunTzuygZMWKEHXHEEZaNOnbsaM8880zS311wwQXumk7l/ffftx122KEcty4alNePGTMm6e9OPvlk94xr2LChtWzZ0nbccUdXNmnTpo17hqjMUr9+fatZs6bdeeedZb5t559/vp111lmlWke7du3shRdeKPHfv/baay7PqugyjiqXKoOF/+899thj9qtf/apU37Fo0SJ3fr///nsrS2vXrnXl1Q8//LDE6/jXv/6VMk9P13777We33367lbWDDjrIbrzxxpS//7//+z8bPHiw7bbbbu5ead68ubt39tprL5dvffHFF2W+TSgbqqtNnDjRsk1Z5EPnnXeenXPOOSX+e5VXi3NfP/nkk65uqzqmtl31WT0z6tWr554pStPva9Wq5Z71Zc3nb99++22J1zFq1Cjr2rWrVbT8QHk0Wdn0L3/5i51wwgmRKncR9PpFYRWkYAagG2flypXuJkpG0WRFnfU34cBYTk5OfF36v27G4lChKtWNoUzCf8L0MNTFrO1SEOV///ufLViwwH30/6VLl9rq1avdG69169aVuhCvfQwWnpQZSbJjduutt7rf61OjRg13fLWc/6igq33S8TrggAOKtR2ff/65HX/88W7/lSmpMHDbbbcV+mbvk08+sd/97ncuGKjvVqFbN70ClCoUzps3z21L8KN177rrri6zTzc4pYKSvkN/t/vuu9see+xhe+65Z7wAowCHP2a6jlToT2XhwoWu0PXrX//a9t57b+vWrZsde+yxdscdd7jzW150fFI9HFNdi0E6nnooIT26h5s0aeL+r3tFgeqguXPnuvTw9a1r48wzz0xI03L+vixLZbFeXVfJrotkwSL/Bm/jxo3xPEfbkJub6/4tKV2beiYE3zj6/CnVA1x5ga55bX8wH9P//Tbp2Dz44INpb4f2Scv36NHDFeJ0/o855hhX4UlF2z1y5Eg78MAD3TWibejSpYtdfvnl8YKZXr6E8zGtW99z9913u2NalMmTJ7u8VQEK7b8qj8rD9F3t27d3hU8FFETHQMelMCrk/uEPf7BDDz3U5YnafgVEXnzxxTIPYIalumaLysd03ArLm6sSVTSSvdgS3Uf+mZasoqXzu2bNGhfU1/NMZRNVJn766SdXZlG5RJ8rr7yyRNuma/uDDz5I+jvdl8laFiggooK3XhBce+21dvXVV7uftQ3alvD1U9T1XRjlD8rLinpmejpe6dwTyj/C2xq+h3X9Kr/VR2WG8PWt45PqRav2W+UfrUN5jc6x7nWln3rqqW45HReVYVKtp7THrDT5fGHPmmTXhMo7KkcHy/aFPRfSab2i9BkzZhTIc325NxlVRvXS6ze/+Y1NmTLF3SvLli1z945eOOoFg8qAb7zxhkWJnl8qy6jsrOeaysu6L/Viv7CGCgpq77TTTu486ZmlY/PEE0/E76Hws1DXhQLZp59+uju+6TjxxBNdfWGXXXaxTp06xcv0+r+ekbo/fvjhB7esD9Ckojzv/vvvt379+tk+++zj6i567l9//fX23//+18pLcfOh4txT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y1522WWuJcl9993nWnopuLVhwwZXAQ/q16+fGyfsnHPOSbulV7t27dyg+ppNsrxb2zwzdUNkW3qduV89WkWxT4XukyalaNasmQuk+fsNhVMepYAixwxFev1Wi6x+Qyvka7jfSobjhrSQR5UJ7rfKccz0Qjqq9tprr0xvArLYmizJozLe0stTBVk3zQMPPOC6IxYW9Nptt93sgw8+iLcGa968uX3//feu5VeQWsKolUsqtWrVcp8wVe71CfKV9WTbnWp/kklYrwJS2/8ixVYmSVegKWl6iiHaip1erdTpCnqEj6GXLD3V8qmOe3HTS3WeSpjOPhWenup7AQAAAACo9APZJ7Nw4UIXDSzMhAkTbJ999on/3L9/fxszZkzCMuqapa6N+++/f7ltK4Do05iBZ599tu24446um2ivXr1cHhSkIL26l2ryjEMPPdS++iqxu7LMnz/fBgwY4PK3Nm3auK7VwVZwAFBS5FMAAABZGPQ67rjj7JVXXrFNmza5rlfvvvuunXfeeXbDDTe436s11+mnn27/+c9/XLcqjRt05ZVX2tdff20XX3xxfD3XX3+9PfbYY/b666+7n7/99lsbNGiQGx+M1iQASkPdpNWFWmOZaWy1Cy+80I4//niXD8moUaNs9OjR9s4777imuxdddJEde+yxrhLqaczC3r17W9++fV33aU3Y8dFHHyUdUxAAiot8CgAAIAuDXpqV8Z///KcblFsDcCt4pZkb/Rhcv/rVr1yXRb291JtJDYytcYA++eQT9ybT69ixo7366qtuYHotp4HuFRQbPHhwBvcOQGWnwfnVdXr48OEub9FkGmeccYYdeeSRrjKogP21115rjz/+uO2yyy6u2+Ypp5xiAwcOdH/jjRw50k3Icf7557tAfOvWre3pp5+2ESNGuMolAJQU+RQAAECWBr30RlHBKrXgWrFihQtm6Q2jV79+fVdQ++KLL9wsjXp7qSCZAmRhmllOhTt1adTMcGoxBgCloZYTqjAGZ5pUKwl1n1ae895779lOO+1UYOzAk08+2caNGxf/+eWXX3aVzCDlYwcccIC9+eabFbAnAKKKfAoAACA1+v4BQApqUXrHHXe48XGuuOIKa9WqlRsXR9191BJVLSA6depU4O86dOjgWl5s3brVtbrQzLSpltPvUkk2w6yoO7ifjTPqs3yyTyXcp5gmPNGUJz//bZ5m4Q3uU07MTQQcTHdTpOTELD+m+YGLTtdbs1yXnpMwn3CuxSw3xywvlpMwP3CqdG2j5mfZ9ss2B9OTbXu1X45HeZ+n8DHOVpnOpwAAALIZQS8AKIRaQ2h8QY2Ho8qfWlNo6ukNGza4FqiaQTZZywtVvjVGjiqkhS2n1qmpqMt2svF0pk2bZvXq1XP/b9GihdsutXBVa1hP3cb10Sy2avXhaSBrtd7QPmzcuDGerlYg2latOxg06Nq1q9WsWdOmTJmSsA09evSwLVu2uNYknoIIalmi79PYQl6dOnWsW7durlWvumJ5Gixb3dYXLVpkCxYsiKezT2WwT/k7/7xPuT/YFqtu0/N33L5Plm89q/1oq62OzcpvuX2fbIt1q7bIlsXq25xY8+37ZButS7XFtijW2BbEtg8t0CJnrXXIWW5zY01taazB9n3KWeU+s/N3cN8R36ecZbZDzjqbkd/aNlrN7fuUu9ga20ablt/O8gIN0LvmLrSats2m/LIv8fOUl1ch5ynYcirbZTKfIjjPPpVonwJB7sgF57dtq7DzVFmC8wCQSTmx4FOqilNBTQVhFZobNmxY7t/3xOfrLaoG7fdzhRzIlvutJN566y3XVfrvf/+7/eY3v3Fp6oqtMW9UQTzmmGPs008/teeffz7h7xTUaNmypasIqgWF9lPLqZIdpLEHVaG89dZb065MtmvXzo2v448ZFS/2Kem2j/9rNCuTSu93feK+ltN50hiizZo1y+o8KhvyqZtuuilpcF6zR4aD8//973+TBn3VkixZ0PfLL79MGvSdPHlyqQPZOr/JAqRLlixJGiBVcDRZgJR9KuE+Lflu+z4VEpxfFUsenF+Snzw4vyA/SXA+d7n9N79ZweB87iqbmdeyYHA+d519mdemYHA+Z6NNztup6OD8DrtV2HlSgFvDxWR7PlXVy596CRFVe+21V6Y3AVlsTZbU9wh6BRD0KjsEvVBZMsHCaCwbzRj7u9/9rsC2q0WExhi8//773SxnQR9//LGdddZZ9t13PxfqVcjVrLSasTbo6KOPdstpltqoHDNkideTBygiod/QCvmaynK/ZTqfIjjPPpVon34JzEcyON/n2go7T5UlOJ9NCHqVLYJeqAxlqYwOZA8A2U4FyzC9ca1Vq5adeOKJrluaxsUJGjt2rA0YMCD+c//+/W3MmDEJy6i71WeffeZmmwWAyppP6TtUkA1+fOXef/z26d9k6arYp5OuIEB43T5dn3TTJZzugxThbUyVzj6Vcp9yYvGPFtcnmKbPz/uUmK7AltvGNNNz4+mJ69ZybtvTTP9llwpsY9Jtr+DzlO3UGlB5SWE0e6xaB4Y/ai2qMQu92rVrJ11OrVQBIBWCXgCQgroHXX755W7mMnVT0Oedd96xE044wbWIUGFs6NChNnjwYFu4cKF7c/vMM8/Yiy++aFdffXV8PZdddpm9//77brwdvZnVspol7aqrrnJvaAGgpMinAGQjjRd47733JnSVTeWSSy5xrdaCH3XT1sQcam3qqVWpAvjhZdXiFQBSyf7XAwCQIb///e9dk1yNV3Paaae5t6p77LGHDR8+3LWKEFUa9TZWM6fpTaa6CI0fP9692fTUxWjixImuUjlkyBCrX7++Gyfnuuuuy+DeAYgC8ikA2eahhx5yAfNgt8ziGjdunLVu3drlVwBQGozpFcCYXmWHMb1QWfp4VyYcM6SNMb1KjfutZDhuSAt5VJW539SdU629mjffPvFAOg499FAXgB84cGCp1xXEmF5lizG9UBnyKLo3AgAAAACywhdffGHz58+33/72twV+d99997mZQDWr7D777GOPPfZYRrYRQOVB90YAAAAAQFYYMWKE62rtB/P3jjrqKNeF+4033nDdsz/55BM3XqFmCr3gggvSnmFW9Dd+htHynrnULxPuYOUnfQina91KK026n0whVXq462lJ0v1xjOQMs+yTlcU+hbcnUwh6AQAAAAAybtGiRS6o9cADDxT43YQJExJ+Puyww+yee+5xYxqmCnoNGzbM/T5s2rRpbqIPadGihXXo0MHmzp2bMPB+27Zt3Ucz4Kp7lte+fXsXdFO3xY0bN8bTO3fu7GaT1LqDQQPNcqvgwOLFixO2oWXLlm654OyWCiRoAH9NSqLB/IPBCG2nvi+4LVq3Wr2tW7fOfbw6deq4bdGywW3UeI0NGjRwEwAEg4Hqgla3bl1bvnx5QqBC69Z3LFmyJCHIoi6m2qcpU6Yk7FOPHj3ctk+fPj2epuU0Npu2ZdasWQnb2K1bN7f/c+bMSdiWLl26uGtBMxF75X2e1IKwZs2a7NPqstunefPmWTZgTK8AxvQqO4zphcrSx7sy4ZghbYyXU2rcbyXDcUNayKOqzP1W3HG4rr/+etuwYYNr7ZWOr776yo488siUs0Qma+nVrl07F9zxx6y8W9vMnDkzsi29FPQIolUU+5Qb2CcFVzUDdKbzKFp6AQAAAAAqhCrDqhSHqeWKxuj69NNP016XWn9pbK9U1EpJnzBV7vUJ8pX1sHA3y6LSw+v1ASL/b1iydB9sKq/0ZPtZkvTwvhaWru1Ilp7quBc3vbTnqSTp7JMVmp7qeysaA9kDAAAAAMrdpEmTXIsPdX0Ke+KJJ+zggw+2XXfdNenfHnjggTZ+/HjbunWraw02evRou/XWW+2OO+6ogC0HUFkR9AIAAAAAlDuND6SxtGrUqJGQri5VmpnxiiuuSPm3F110kQ0fPtyNGaRxr55//nnX0kvjEAFAKtnR3gwAAAAAECnh8afUFTE8oLvvUvXNN98Uuq4zzzzTfQCgOGjpBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMgh6AUAAAAAAIDIIegFAAAAAACAyCHoBQAAAAAAgMjJaNDr448/tpNPPtlatmxpDRs2tAMPPNDee++9hGXy8/PtlltusR133NEaNWpk/fv3tx9//LHAumbMmGGHH364NWjQwHbddVd78MEHK3BPAAAAAAAAkE0yGvQaMmSIHXvssTZnzhxbvny5/elPf7KBAwfa7Nmz48v85S9/scmTJ9u0adNs2bJl1rt3bzvmmGNs06ZN8WUWLlxoffv2detbs2aNvf322zZq1CgbPXp0hvYMAAAAAAAAVTbopVZdZ511ltWrV89q1KhhJ5xwgp100kn25ptvxoNZI0eOtCeffNJ22GEHt8zll19uu+++u/3jH/+Ir+e2226z0047zY4//njLycmxjh07uoDXddddZ3l5eRncQwAAAAAAAFS5oFf9+vULpG3cuNEFweS1116zI4880ho3bpywjLpEjhs3Lv7zyy+/bKecckrCMt27d3ddHT/77LNy234AAAAAAABkp6wZyF5dF0eMGGFTp051QS2ZOXOmderUqcCyHTp0cL+TlStX2uLFi4tcDgAAAAAAAFVH9UxvgLoq/u9//7P169db7dq17c4773T/yrp166xVq1YF/qZp06a2du3a+DI1a9a0unXrFrpcMps3b3YfT+OBybZt29xHcnNz3UcD6uvj+XR1n4zFYkWmV6tWzXW99Ot1YnmBuOP2df+ypuTpOdXM3HqTpSstlkZ6jllObiHp4S6hqdJzzXJykqZr38NdS3UMJJxevXr1AsvrWGn58HFPlV6u56mQbWefSr5P4e0BAAAAAKAsZTzo9e2337p/VZFWq6xLL73UzcT48MMPu+6Pq1atKvA3SlPXRdEyW7Zscd0i69Spk3K5ZIYNG2Y333xzgXQNmu+7WLZo0cK1GJs7d64tXbo0vkzbtm3dR4Pur169Op7evn17N/6Y9kHb5HXu3Nl109S6fdCg7qo829ios8Vya1jdlV8lbMOGJntbTv5Wq7N6VjwtlpNrG5t0tdxta6322jnx9PxqtW1To85WfctKq7l+fjw9r0YD29ygg9XYtMRqbPwpnr6tVlPbUm8nq7lhgVXfvCKevrVOK/eptW6eVdu6PVi4pV4721armdVe853l5m2fQGBTg/aWX6Oh1Vn1teW4ANrPtE95ebVtypQpCfvUo0cPd66mT58eT1NgpGfPnu4Yzpq1fV91Lrt16+ZaAGqiA08zeHbp0sUWLVpkCxYsiKeX53mSrl27uuAq+1R2+zRv3ryE7wUAAAAAoCzlxIJNQrLAN998YwcddJALWD3wwAP2zjvv2NixYxOWefrpp+1f//qXm6XRV6S13N57752w3G677eaW69WrV9otvdq1a+dmkmzYsGG5t7Z5ZuqGyLb0OnO/erSKYp8K3Sfd482aNXOBNH+/oXDKoxRQ5JihSK/fapHVb2iFfA33W8lw3JAW8qgywf1WOY6ZXkhH1V577ZXpTUAWW5MleVTGW3qFacZGHRjp27evXXvtte5gBQ+SgmADBgyI/9y/f38bM2ZMQtBLrVTUtXH//fdP+V21atVynzBV7vUJ8pX1MB8gSDc9Yb0KSG3/ixRbmSRdgaak6SmGaCt2erVSpyvoET6GXrL0VMunOu7FTS/VeSphOvtUeHqq7wUAAAAAoNIPZH/cccfZK6+8Yps2bXKtUN59910777zz7IYbbnC/33XXXe3MM8+0s846y1asWOG6XN1zzz2ue9W5554bX8/1119vjz32mL3++uvxLpODBg1y44NRsQYAAAAAAKh6Mhr0GjJkiP3zn/904xNpLCIFrx588EE755xz4svcd999bkwiNZ1s3ry5vf/++65box/sXjp27GivvvqqG6NLY3j16dPHLr74Yhs8eHCG9gwAAAAAAACZlNFmUL1793afwtSoUcPuuOMO9ymMBtn+6KOPyngLAQAAAAAAUBlltKUXAAAAAAAAUB4IegEAAAAAACByCHoBAAAAAMqcxm1etmxZocs8+eSTVq9ePWvcuHHC51e/+lWBZT/44APr0aOH1a9f37p06WIvvvhiOW49gChgakMAAAAAQJlZv369Pfroo7Z06dIil83Ly7MjjjjC/v3vfxe63JdffmlnnHGGPf3003bIIYfY1KlT7cQTT7QmTZrYUUcdVYZbDyBKaOkFAAAAACgTDz30kLVo0cKuvfbaMl2v1nfddde5gJfsu+++ds8995T59wCIFoJeAAAAAIAyceGFF9qGDRts06ZNZdpybOLEiXbSSSclpPfr189mzZplCxcuLLPvAhAtBL0AAAAAABmzePFiO/vss61du3bWsmVL69u3r3399dfx38+ePduN89WsWbOEv6tZs6a1bdvWBb4AIBnG9AIAAAAAZESbNm1cd8jjjjvO7r//fjfG16hRo+zggw+2mTNnWqtWrWzdunVu7K5kmjZtamvXrk36u82bN7uPt2bNGvfvtm3b3Edyc3PdJz8/3308n67ticViRaZXq1bNcnJy4uv1/DLBZUXLJkvXupVWmnStW59U6cH9LGm6P45BOgaiYxNUvXp1tx3BdK1Dy4ePe6r08j5Pqbadfcop8T6FtydTCHoBAAAAADLimGOOcZ+gP/3pT/bhhx/as88+a1dccYWbrXHVqlVJ/17pDRo0SPq7YcOG2c0331wgfdq0aW7GSFHArUOHDjZ37tyEgffVgkwftTJbvXp1PL19+/ZuVsoZM2bYxo0b4+mdO3d2rdG07mDQoFatWi44oNZsQWrRpuWCs1sqkKAg35YtW2zFihUJwQhtp74vuC1at4J+Cgrq49WpU8dti5YNbqOOo46VjlkwGNioUSOrW7euLV++PCFQoXXrO5YsWZIQZGnevLnbpylTpiTsk2bW1LZPnz49nqblevbs6bYl2CJP29itWze3/3PmzEnYFs3MuWjRIluwYEE8vbzPU9euXV3LQfZpdZnt07x58ywb5MTCoeIqTJF/nTyd6IYNG5b79z3x+XqLqkH7/fwQAbLlfosCjhnS9vqtFln9hlbI13C/lQzHDWkhj6oy95uCOKrMK0hSXFdddZVrMXL33Xe7llwKwGhdqtx7qrgr/dtvv7Udd9wxrZZe6kKp4I4/ZuXd2kat1aLa0ktBjyBaRbFPuYF9UnBVXZIznUfR0gsAAAAAUCFUGValuDCqdL/33nt25ZVXup/VOkndHceOHWvnnHNOfLnx48e7Vi7JAl6iVkr6hKlyr0+Qr6yH+QBBuunh9foAkf83LFm6DzaVV3qq41/c9PC+Fpau7UiWnuq4Fze9tOepJOnskxWanup7KxoD2QMAAAAAyt2kSZNciw91ffKeeeYZu/TSS11XLpk/f74NGjTIatSoYSeffHJ8udtuu81uvPFG+/TTT93PkydPtssvv9zuuuuuDOwJgMqCoBcAAAAAoNxpfCCNpaWAlnf00Ue7QNhvf/tb97v999/fjVs0YcKEhJYivXr1sscee8wuvPBCNzbV4MGDbcSIEXbkkUdmaG8AVAbZ0d4MAAAAABAp4fGn9tlnnwIDumvg69tvv919itKnTx/3AYB00dILAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAAAAAAAAkUPQCwAAAAAAAJFD0AsAAAAAAACRQ9ALAIrw3HPPWffu3a1Ro0bWsWNHu/LKKy0Wi7nf5efn2y233GI77rij+33//v3txx9/LLCOGTNm2OGHH24NGjSwXXfd1R588MEM7AkAAAAAVB0EvQCgEPfcc4/dfvvt9tBDD9nq1avtgw8+cIErBbvkL3/5i02ePNmmTZtmy5Yts969e9sxxxxjmzZtiq9j4cKF1rdvXxsyZIitWbPG3n77bRs1apSNHj06g3sGIEoIzgMAABRE0AsAUpg9e7bdcccdNmHCBDvggANcWps2bezmm2+2atWquWDWyJEj7cknn7QddtjBatSoYZdffrntvvvu9o9//CO+nttuu81OO+00O/744y0nJ8dVSBXwuu666ywvLy+DewggCgjOAwAAJEfQCwBSeOyxx+z000+3li1bJv39a6+9ZkceeaQ1btw4If3kk0+2cePGxX9++eWX7ZRTTklYRi0yVCn97LPPymnrAVQFBOcBAABSI+gFACl88skn1qtXL3v88cetR48e1rx5czvwwANdCwiZOXOmderUqcDfdejQwf1OVq5caYsXLy5yOQAoCYLzAAAAqVUv5HcAUKUtWbLE7r//fmvVqpVrJaEg1euvv24DBw60d99919atW+d+F9a0aVNbu3at+7+WqVmzptWtW7fQ5ZLZvHmz+3jqciTbtm1zH8nNzXUfdWPyXZmC6Wqh4cf1KSxdLULUusOvN5gu4ZYeqdKrV6/u1htM13q1fHgbU6WzT2WwT7Gcn9Pt57/Ns5zEfcqJmVYbTNf/quXELD9mlp9Gut6a5br0HNu+R0qPWW6OWV4s55dvLzxd25iTY7btl20Opifb9mq/HI/yPk/hY5zNwfnLLrvMBef//ve/27x582y33XZzY3gdffTRZRacP+igg5J+P/kU+1SifQrc75HLp7Ztq7DzVFnyKQDIJIJeAJCCglV77LGHG9fGU9efTz/91B599FGrX7++rVq1qsDfKU2tI0TLbNmyxTZu3Gh16tRJuVwyw4YNc12UwjQuT7169dz/W7Ro4Sqlc+fOtaVLl8aXadu2rfuo65PG+PHat2/vujhpwGptk9e5c2fXEkTrDhbGu3bt6o7DlClTErZBLd+0X9OnT4+nqXDes2dP932zZs2Kp2u/u3Xr5sYSmjNnTjxdA2p36dLFFi1aZAsWLIins09lsE/5O/+8T7k/2BarbtPzd9y+T5ZvPav9aKutjs3K3946qI5tsW7VFtmyWH2bE2u+fZ9so3WpttgWxRrbgtj21kItctZah5zlNjfW1JbGtl/HbXNWuc/s/B3cd8T3KWeZ7ZCzzmbkt7aNVnP7PuUutsa20ablt7O8QAP0rrkLraZtsym/7Ev8POXlVch5UvCoMsh0cJ58in0q0T4F7uvI5VNTplTYeaos+RQAZFJOLPhqporT20k9YPQwatiwYbl/3xOfr7eoGrTfzwVdIFvut5JQpXHfffd1Y9oEqUXFs88+a8cdd5y98847Nnbs2ITfP/300/avf/0r3g1SBVQtt/feeycsp9YYWk5dKNNtQdGuXTtbvnx5/JjR2oB9Srrt4/8azRYUSu93feK+ltN5UlC6WbNmWZ1HyV577eVaYQWD83LNNde4ba9Vq5bVrl3b7rzzzoTfa2D7E044webPn+9aeim4tWHDhgLB+X79+rnlzjnnnKTfTz7FPpVon37JoyKZT/W5tsLOU2XJp6p6+VOB4ajSMwjI9voeLb0AoJCg19ChQ+3KK690lUZPb6nVDUgznV177bUuQw9m5AqCDRgwIP5z//79bcyYMQlBL739VeuJ/fffP+X3q7KqT5gKzfoE+UJwmC94p5seXm9J0lVQT5aeahuLm84+pbHtOYnvs6onVN9+WSQneboqfLnFSo8lHSBUFVArRnr1VOnh79SGV8B5SnWMs40GpN9ll10KpKuVajA4H6ZWO2qRI02aNHFjFn7//fcFgvPB5ZIhn2KfSrRPSe73yORTgf0mnwKAzGMgewBIQQM977rrrq5Lo7oQqKvCU089Zc8884wNGTLE/e7MM8+0s846y1asWOF+f88997huC+eee258Pddff70bbFpdjuTbb7+1QYMGuZYXFFgBlDY4r1kYN23alJAeDM6/9dZb8bG2igrOB6UTnAcAAMhmGQ16qXnviy++aH369HHjTagLkApgqhDKDz/84JrZa1yA8Ef924PUPF9/q+ZzfqruYFNgACguvb1+9dVXXSsHVfrUGuKf//ynTZgwwY2nIffdd5/7vZp3q6XE+++/77o1BluGdezY0a1HY99oDC/leRdffLENHjw4g3sHIAoIzgMAAGRp0Et9OzX46tVXX+0Kaj/++KMdeOCB1rt3b/dmUUExVTrVXz38UWDLW79+vfsbvc3UGBJTp061jz76KOnAqgBQHBrYecSIEW5mM+U16ibUvXv3+O9r1Khhd9xxhwvEqyXFuHHjbMcdtw/G62nwWuVLyts0+Ox5551XwXsCIIoIzgMAAKSW0Vd3apWlgpf6tnsaH0dvKDXAqmaFScfIkSNdJfT88893P7du3doNJK0CnKbx1gCPAAAAUQ7O65OMD87rUxgfnAcAAIiKjLb0UrArGPCSrVu3uub3xRnd/+WXX7ZTTjklIU1TKB9wwAH25ptvltn2AgAAAAAAoHLIqkEa1J1R40906dLFevTo4bo8alwuzZ72wgsv2NKlS13rreuuuy5h8NWZM2e6wVrD1Kxfv0sl2TTboimW/TTL5Tp9cywvEHcMjz+WIj2nmg5UinSlxdJIzzHLyS0kPXF65dTpuT9Pq5MkPTwdsz8GkZhmm30qk30Kbw8AAAAAAJEMeq1cudKNG6HxbtRySzSIfa9evaxp06b24YcfutZfarmlwVg1QKvGm5B169a5MSzC9HdaXyoatyLZuF/Tpk2zevXquf9rcH0FzzQGj4JuXtu2bd1HU3lrbDJPXTLVymzGjBm2cePGeLrG0tAA/Fq3DxrUXZVnGxt1tlhuDau78quEbdjQZG/Lyd9qdVbPiqfFcnJtY5OulrttrdVeOyeenl+ttm1q1Nmqb1lpNdfPj6fn1Whgmxt0sBqblliNjT/F07fVampb6u1kNTcssOqbV8TTt9Zp5T611s2zalu3H7ct9drZtlrNrPaa7yw3b/vsUJsatLf8Gg2tzqqvLccF0H6mfcrLq+1mjgpSIFMD6Go2KE+BEXWn0DHUoLqezn23bt1s2bJlNmfOnIQusQqKavykBQsWxNPL8zxJ165drWbNmuxTGe6TgtoAAAAAAJSXnFiwSUiGfP7553baaae52YXUqkstQQqjWYc0FpgGjPYV7E8//dRVsoM0AKsCX7feemvaLb3atWvnBsP33SvLs7XNM1M3RLal15n71aNVFPtU6D5pQgqNt6dAWnG6M1dlyqOU33HMUKTXkz/3IqHf0Ar5Gu63kuG4IS3kUWWC+61yHDO9kI4qTZACZHselfGWXq+99poLTj377LOuVVc6dtttN7e8p66N33//fYGgl1rCqFVYKrVq1XKfMFXuw9Nz+8p6mA8QpJuesF4FpLb/RYqtTJLuxkFLlp4iWFjs9GqlTlfQI9UU58nSUy2f6rgXN71U56mE6exT4empvhcAAAAAgEo/kL1aVF144YU2fvz4tANeomm499lnn/jP/fv3tzFjxiQso+5Wn332WbwLJAAAAAAAAKqOjAa9NDj9wIEDbY899kj6+x9++MH69u1rH3/8sesOpeZxd911l2vldf3118eXu+yyy1x3x9GjR7vlFi5c6GZzvOqqq1z3KQAAAAAAAFQtGQ16qUviI488YvXr1y/wueaaa6xNmzbWr18/u/rqq91A3DvvvLNNnjzZJk2aZLvsskt8PRrEfuLEia61l5bTgNtHHHGE3XDDDZncPQAAAAAAAGRIRgfVGT58uPsURuN96ZPOOF9vvPFGGW4dAAAAAKCkNLP4N998Y82bNy90OTVsuO+++1wPn5UrV7rZx2+66aaEoWp23313++mnn9wYs0GjRo2y3/3ud+W2DwAqN0aSBgAAAACUmfXr19ujjz5qS5cuTWv52267zU488UQbOXKkNWjQwN5880079dRT7a233nK9eGTz5s2ud0+PHj3KeesBRAlBLwAAAABAmXjooYfc2MoaazldL730UsIM5BrX+fTTT7fXXnstHvQCgEo3phcAAAAAIDouvPBC27Bhg23atCntvwkGvLzFixdbw4YNy3jrAFQ1BL0AAAAAAFnjmWeesY8++sjOOuusAun77befNW3a1Pbcc08bNmyYbdu2LWPbCSD70b0RAAAAAJBx6hKpAeyffPJJGz9+fMIA+AcffLD7/bPPPms777yzffXVV/b73//eVq9ebX/961+Trk/jgOnjrVmzxv2rQJkPluXm5rqP1h3skunT8/LyLBaLFZmu1moaZD8chPPLBJcVPyB/OF3rVlpp0rVufVKlh7ueliTdH8dkLfZ0bIKqV6/utiOYrnVo+fBxT5Ve3ucp1bazTzkl3qdsCUgT9AIAAAAAZJRmZtQ4Xo0bN7YvvvjCmjRpkvD7p556KuHn7t272z//+U878sgjUwa91BLs5ptvLpA+bdo0q1evnvt/ixYtrEOHDjZ37tyEgffbtm3rPrNnz3aBNa99+/ZuVsoZM2bYxo0b4+macVLbrnUHgwa1atVywQF11wxq2bKlW27ZsmUJgYRWrVrZli1bbMWKFQnBCG2nvi+4LVq3Wr2tW7fOfbw6deq4bdGywW2sX7++myhg1apVCcHARo0aWd26dW358uUJgQqtW9+xZMmShCCLgpHapylTpiTskyYZ0LZPnz49nqblNC6btmXWrFkJ29it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bI899rBLL73U7r77bpd24403um5WamXm3XbbbXbyySfbnnvuaQcccIBNnjzZLr/8cnvsscfKdZsBVG7J27+l0SRWmWJwVg8AyLSRI0fGm9Gqaa7G+Lr//vszvVkAUABlKQBVMU/SOEIa00hltKDnn3/etQDbZZddXKstDZqtll7Bblm9evVyAa4LL7zQjY2k1mEjRoywI488sly3GUAVbOmlQaM1vS0AZBMNsHj99dcnpPH2D0A2oiwFoCrkScEBxEXjsIZnkvPdFx9++GH3KUyfPn3cBwDKNOilwQEVTVempa5CehPgp+bUwIA//viji8RrEMKTTjop7S8HgLKUbKBSjVMBAJlGWQpANiFPAlBVpBX0Uj9rNUENjsx/4IEHuiao+++/v3300Ud2xhln2J133mkrV660P/zhD+W93QBQgMbwCtu8eXNGtgUAgihLAcgm5EkAqoq0gl7z5s1L+TsNEH3MMcfYoEGD7Pzzz3eDC5IpAsiERYsW2dlnnx3/WW8vNSZEeJYgAKholKUAZBPyJABVRYlnb5wxY4a1adPGpk+fbuedd55La9euna1bt64stw8A0jZ8+PD4W0s11VfLL83uExwEFQCyBWUpANmEPAlAFJUo6KWM79RTT3UDRC9fvtxatGgR/x2tKQBkCm8hAVQWlKUAZBPyJABRVewc7KeffrLevXvbOeec4/p7qyWFWlR41auXuPEYAABA5FGWApBNyJMARFlaOdiUKVNc96BXXnnFXnzxRbvtttts4MCB7nd6C6Axc9QUVpmjxs4BAADAdpSlAGQT8iQAVUVaQa/LL7/c5syZ42buuP/+++MZouyzzz42btw4u/DCC+3//u//rGfPnuW5vQBQwFFHHWXVqlVzhTINXq+P/3+yNM1EpFmLAKCiUJYCkE3IkwBUFWkFvTRlrXz55ZfuLcCTTz5pzz//vLVu3drOPfdcN73t66+/btOmTbO33367vLcZABJceumlVqtWLatZs6YbyF5vLv0nWdBr9913z/QmA6hiKEsByCbkSQCqimJ10O7WrZu98MIL9uijj9rBBx9sEydOtF122cX+85//2Icffmh77723+xkAKtJvf/vbTG8CAKSFshSAbEKeBCDqSjQqoaawrV27tmsGO3XqVGvcuLEdd9xxZb91AAAAEURZCkA2IU8CEFUlnorjzDPPtN12261stwYASuGLL76wO+64wz7//HNbunSpNW3a1Pbdd1+78sor7fDDD8/05gFAAspSALIJeRKAKMotzR8fcMABZbclAFAK77zzjh1//PHWr18/++STT2zNmjVunApNvz1kyBA3ECsAZBvKUgCyCXkSgKgpcUsvAMgm99xzjz311FN2yCGHxNOaN29uAwYMsD333NMNdt+3b9+MbiMAAAAAoJK09AKAbLFkyRLr2rVr0t81bNjQli9fXmZjXuy1114F0h9++GFr3769NWjQwA499FD76quvCiwzf/58F4Rr1KiRtWnTxm6++WY3oyQAlBXyKAAAgO0IegGIhMMOO8zuvffeAumqsP3lL39xlbzSeumll2z8+PEF0keNGmWjR492XSxXr15tF110kR177LG2ePHi+DLr16+33r17u9ZmCsBpkFhNF65KJQCUBfIoAACARAS9AETCTTfdZNOmTXOtvS6++GIX6PrDH/7gptn+6aefSl1xW7RokVvn3/72t4T0TZs22bXXXmuPP/64+67c3Fw75ZRT3OxHw4cPjy83cuRI6969u51//vlWvXp1a926tT399NM2YsSIMmuFBqDqIo8CAAAoiKAXgEioV6+evfLKK25cr27dulmdOnWsZ8+ertXDq6++6n5fUrFYzAYPHmx333237bDDDgm/e++992ynnXayzp07J6SffPLJNm7cuPjPL7/8sqtoBmldGjD2zTffLPG2AQB5FAAAQHIMZA8gUtTSK9XYXiWllhOdOnVyM0OqAhk0c+ZM97uwDh062Pfff29bt261GjVqFLqcfpfM5s2b3cfTjJSybds29xG12tBH3TiDY+/49Ly8PFchLiq9WrVqlpOTE19vMF20fDrpaiGi9QbTtV4tH97GVOnsUxnsUyzn53T7+W/zLCdxn3JiptUG0/W/ajkxy4+Z5aeRrrdmuS49x4KjPuVazHJzzPJiOb98e+Hp2sacHLNtv2xzMD3Ztlf75XiU93kKH+Nslqk8Ssin2KcS7VPgfo9cPrVtW4Wdp8qUTwFAphD0AoBC/Oc//3GtxyZNmpT09+vWrbMmTZoUSG/atKkr2GqcnMaNGxe63Nq1a5Oue9iwYUm7Zaobp2+51qJFC1cpnTt3ri1dujS+TNu2bd1n9uzZbgwfTwNZq/XGjBkzbOPGjfF0tQLRdmrdwcK4Aog1a9a0KVOmJGxD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qyj2qdB90oQUzZo1c4E0f7+hcMqjlN9xzFCk15M/9yKh39AK+Rrut5LhuCEt5FFlgvutchwzvZCOqr322suiivMWnTwq42N6lcRuu+3mWpB46tr4/fffF1hOLWHUyiWVWrVquYMf/PjKvf+ogi76N1m6KvbppCsIEF63C0gp3X2qhT4p0iVlem6a6blFpFdLMz0nZbr2N7iv/hgkS/95lxLTfeAlfNxTpZfneSps29mn0u0TAAAAomP+/PluGBpVdNu0aeN61QRfgKaalEy9EsIf9by544474svVrl076XJq/AAAkQp6TZgwwfbZZ5/4z/3797cxY8YkLKPuVp999lm8CyQAAAAAoHysX7/eevfubX379nU9Z6ZOnWofffRR0uFkgi655BLXAyD4WbFihbVq1cqOPvro+HLqoaOGDuFlNXkZAFTKoNcPP/zgMs2PP/7YvSFQ87i77rrLnn32Wbv++uvjy1122WWuu+Po0aPdcgsXLnSzOV511VWu+xQAAAAAoPyoxVb37t3t/PPPdy36W7dubU8//bSNGDHCBcGKQ8PY6O81piwARDbopSax/fr1s6uvvto1Xd15551t8uTJNmnSJNtll13iy2kQ+4kTJ7rWXlpOmeMRRxxhN9xwQ0a3HwAAAACqgpdfftk1PAjSJEtqiaXJyIpDgbIrrriijLcQQFWUVYPqhMfUr1GjhhuMXp90xvl64403ynHrAAAAAADJzJw50421HKaZu/W7dH3xxRdubLDf/va3BX533333uVZgmh18p512cl0jzz333JTrSjZxmWiCJz/JU3lPHuWXCdd1/bi74XStW2mlSfdj9KZKD4+zVpJ0fxyjOsmX/44onKdYaFv8z+V9nsLHOFOyKugFAAAAAKh81q1b53rghDVt2tTWrl1brFZeGr7GByG8o446ylWm1dBBLcg++eQTGzx4sKtYX3DBBUnXNWzYsKRjik2bNs0NlC8tWrRwgbm5c+fa0qVL48u0bdvWfTQ5mmaf89q3b+++X7P7bdy4MZ6uCdTU60jrDgYNNHma9mXx4sUJ29CyZUu3nMaiDgYSNJbZli1b3LhmwWCEtlPfF9wWrVvHV8deH69OnTpuW7RscBvr169vDRo0cGOhBYOBmnigbt26rhtqMFChdes7lixZkhA4ad68udunKVOmJOxTjx493LZPnz49nqbl1BNL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5jlnzvZ91QNUD7hFixbZggUL4unleZ6ka9euVrNmTfapDPdp3rx5Cd8LAACAystPLnbllVfa2LFjXfl10KBBrr5V2ARjKp8eccQR9u9//7vQ9X/55Zd2xhlnuLGbDznkEDd52YknnugaPxx11FHlsEcAoiAn5puBZAEFspQ5Nm/e3P38+uuv2w033OAytKCPP/7YzjrrLPvuu+/cz6qMa7njjjsuYbmjjz7aLXf66aenbOmlj6eWXu3atXOD3zds2NClafB8ffSGIviWwqcrkw4ewlTpChpo/4KtW56ZuiHQ2C78BiRFek61X1pYJUtXWiyN9ByznNxC0rcHRgpPz9VJS5p+5n71EgIs/hhIOF2TD+hYBdN1rLR8+LinSi/P81TYtrNPJd8nBaWbNWvmAmn+fkPhlEcpoMgxQ5Fev9Uiq9/QCvka7reS4bghLeRRkbzf7rzzTveS9bnnnounLVmyxDp27OheeKrcl8y//vUv12KrqKDXscce61qRXXDBBQljO99xxx02efLkrD1meiEdVXvttZdFFectOnlUVrf0Ovzww11rFo3fpczS05sDZXhe//79bcyYMQlBL7U8+eyzzxIy3bBatWq5T5gq9/oE+cp6mA8QpJuesF4FpLb/RYqtTJKuQFPS9BS9VYudXq3U6Qp6hI+hlyw91fKpjntx00t1nkqYzj4Vnp7qewEAAFD5KAB17bXXppxc7LTTTitVK7KJEyfaU089lZDer18/15ps4cKFtuOOO5Z4/QCiK6trnepiOHToUBs8eLALarVq1cqef/559yYg2CXrsssuc12sRo8e7Zb93//+5/696qqrUr5RAAAAAACUjdJMLrZ48WI7++yz7e2333bDbOy77752991325577ul+r4YQGq4jXLfTUB0a9kPDbyQLeiXr2SPBMWvLu3eFXybcwUrLJkvXuv0YuyVN17r1SZUeHmetJOn+OEa1F4z/jiicp1hoW/zP5X2esmUM56wOesnVV1/tDmavXr1c6y11ZRw/frx7a+CpH7ci/wp+DRkyxI3xdfHFF9t1112X0W0HAAAAgKqgpJOLacB7jfuqXjv333+/q3CPGjXKDj74YBcsU8OHVOsuav2ZHsNZ1LNI9VkF9oJatmzpllMdNxhI0P4q8LdixYqEYIS2U98X3BatW/uv46NPcNxdbYuWDW6j6skNGjRww4wEg4Hqgla3bl03zE8wUKF16zvUTTUYONFwRNqnKI937K+pKJynxaFrb4899qhSYzhn1ZhemVbRfU6f+Pzn2SejaNB+Pz9EgGzv412ZcMyQNsbLKTXut5LhuCEt5FGRvN+0LZ9++qmrCAepMYIq5bfeWrzz/pvf/MYNcH/FFVe4AEWfPn0KVN5FrcEULEs2mH2mx3AW38otii29wuc6Si29vvnmm8icp1hoW/bee++EfY36GM5Z39ILAAAAAJDd1LVRYzGHAyFqgaPJxYprt912c61IROM7q0WNKtFqGeOptcoPP/zgWu9k5RjOgcCD/zcsWboPYpRXerL9LEl6lMc7Dn9HZT5POaF1+5+ryhjOKUYyBwAAAAAgPX5ysSA/uZhaaXnh1ijJqKXJe++9Z/vss4/7WV291N1RE5oFadgbBbwYxB5AKgS9AAAAAAClovGV33//fTe5mAJbmlHxlFNOSZhcbNKkSa6bk8b78Z555hm79NJLXYswmT9/vpuRsUaNGnbyySfHl7vtttvsxhtvdF0oZfLkyXb55ZfbXXfdVeH7CqDyIOgFAAAAACgVP7mYWnupC6IGxdaYXDfccEPCoNgaQF4BLe/oo492gbDf/va37nf777+/G4B8woQJCd2jNLHZY489ZhdeeKEb6Hvw4ME2YsQIO/LIIyt8XwFUHtnRyRIAAAAAUKlpHK433ngj5e/VXTE8GL1me7v99tvdpyjqJhnsKgkARaGlFwAAAAAAACKHoBcApKApe1988UX3RrFVq1buTeSAAQPs22+/TVju4Ycftvbt27tBVg899FD76quvCqxL41PobzWdd5s2bezmm29OayBXACgM+RQAAEBqBL0AIIXVq1fb/fffb1dffbXNmzfPfvzxRzvwwAOtd+/etnbtWrfMqFGj3ICt77zzjlv+oosusmOPPTah6f769evd3/Tt29eWL19uU6dOtY8++shVKAGgNMinAAAAUiPoBQApqLWDZiHSAKm1a9d2g69ee+21Ll0zBm3atMn9/Pjjj9suu+xiubm5bpaigQMH2vDhw+PrGTlypHXv3t3OP/98NyBr69at7emnn3aDr6pyCQAlRT4FAACQGkEvAEghJyfHfYK2bt1qK1ascLMMvffee7bTTjtZ586dE5bR9Nrjxo2L//zyyy+7SmaQZiU64IAD7M033yznvQAQZeRT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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABLAAAAJOCAYAAACnaf6cAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAApuRJREFUeJzs3Ql8E2X6wPEnbSkUKJT7EJRbUE4FRfFARUWORUEXFhXwYBFQcGVFBMFFVBZFUEREPPACFUEE/iyggqJ4cIkiyiELyqXITYGW0nb+n+ddJ03SpE3btJmkv+/nMx/om8lk3knyZOaZ93BZlmUJAAAAAAAA4FAx4d4BAAAAAAAAICcksAAAAAAAAOBoJLAAAAAAAADgaCSwAAAAAAAA4GgksAAAAAAAAOBoJLAAAAAAAADgaCSwAAAAAAAA4GgksJAry7LCvQtwgFOnTkl6enq4dwPFGLGoeCno+52cnCynT58O6z4ARSGaPqcpKSly5syZcO8GELWiKV4UZ6dPny7wOU6kIoGVRz///LN8/fXXId/ulClT5PHHH8/Tc7Zv3y4PPPCAXHDBBVK1alVJSEgwy9lnny1dunSRWbNmSWZmZoH3rVq1avL2228XeDvIou/Za6+9Jk5Tv359mTNnjt/HevbsaT5f5cqVM5+Js846S2rVqiU1a9aU6tWrS8WKFaVs2bISHx8vEyZMKPJ9L26IRYjmWPTDDz+YWPLrr7/mexuPPfaYXHvttQXaDz5zkYfY6HxXX321PP30034fGz58uDlGej5RpUqVgOcaJUuWlEGDBoV835588km56qqrCrSNyy67TCZOnBiyfULhIV7Ayfr16yf33Xef38emTp0qZcqUMYtnrNR/NVZWrlxZEhMTTazs1KlTyPdt9uzZUq9evQJt49Zbb5V77703z88jgZVHemHerVu3fD138eLFcuTIEb+P7du3T3766aegt7V27Vpp1aqVybw+//zzsnXrVtNCRrf/6aefmn3Uk/fbb7/d7/M1APrLwGsLm9TUVK+MblxcnJQqVSrofTt69KiMGDFCGjZsaJ6nJx233XZbnuoXyN69e80JiwZz/UKec845cs8998ju3bsDPmfXrl3my9GgQQOzP0lJSdK+fXvzxddjpurUqSMul8u9aJ11v2+88Ub55JNPgtq3f/zjH+ZHQbfVqFEjadKkiZx//vly7rnnSu3ataVChQry+eefm3V1+/qjFMjJkyfNRaW+fuvWrc22rrnmGrn//vtl48aNUhB68hfox1o/Exrs/Fm0aJG5K3r8+HHZv3+/eS/27NljPru///67HD58WE6cOGEW/QFG4SIW5Y5Y5OxYlJMSJUqYz4Ae2/zSBJgm3IvyM4fwIzaGNzbaWrRoIe+9917AxzUJ5Y8eK62jnkscOHAgx3ONZ599Nt/7FugCPjY21m+SYMGCBfLPf/5THnroIXPsNNGmf+v5jsZ2T/p+aAyD8xEvcldcz6XsFqHjx4+Xpk2bmnMlTRTddNNNIU16du3aNWBCPyYmRkqXLu33sWHDhpn3V8/TPGOl/qux8uDBg6Yluj4+f/78fO3bX/7yF3niiScCxsqMjIxs5V988YWJjRojfWPld99957Wuxsn8xEoSWHmwYcMGefPNN80XIa9ZdXXLLbfIZ599FjDw6Ic0L5n9u+++W1544QVp166duSDR/dIvsrai6d+/vwl477zzjvkw+9KMqb6ePkc/gPrF1v/rh0i/oLpNmz4WLA24emKwevVqeemll+SXX34xAV5PVPSOgu5Pfn311VfSrFkz+eOPP8xJkQawd99913xBtVzr62vhwoXmgku/yHoRpvujF27XXXedeQ8feeQR97pPPfWU+aHQRQPB0qVLTRZb7+DPmzcv1/175plnTGJHX2Pbtm2yefNm+fHHH80x0UCs+3n55ZebdfXYB7ow0x8EvdjUAKvBSY/ft99+Ky+++KK5KNWLx4cffjhfx1CPndZPs/X+6Hud2/ut74PeXdQfRJvWt0OHDiZI6kUjJ26Fi1iUO2KRc2ORJsM1GabvRd26dWXMmDHZugxpHFG+J+RpaWly7Ngxc5KqMUhjjv596NAhc5LtbxtF9ZlD+BEbwxsbfVuTBEqOB3OusWPHDlNH3T+bft81dmnM1eMQ6DueE72g05gY6DxFj7W/mKjHS2Oh1knfQ72o1GM2efJk81vgOcSCXtTpduBsxIvcFedzKX2Ntm3bmn3TJJbGpJUrV5rX14SZnmuFwn//+9+A52HBxMpTp06Z67JvvvnGq/z666+XdevWmefn52agnn/Zz89LrNT4OnfuXBMjPWOlvl/6uxCSWGkhKP/5z3+sSpUqWRMmTLDWrVtnJSUlWX369LH27NkT1PN///13PQsPuP6wYcOs22+/Pej96devn/XXv/41x3X27dtnxcTEWHv37s322O7du83jf/zxh3m8dOnS1vvvv2/2b+fOndavv/7qXrdu3brmsdwkJydbDRs2tG666SYrPT092+OTJk2ySpQoYa1Zs8bKK92vypUrW0OGDPH7uJbre/LLL7+4y7755hsrPj7eGjdunN/naN0//PBD8/9zzjnHev755/2u17NnT+vyyy8Pel8feOAB67vvvnP/PXz4cOvdd9/1Wufiiy+25s+f7/f5F154ofXoo48G3P7PP/9sJSYmWh999JGVV7of+jmcPHmy38fPPffcXLd76NAhKzY21nyGPLd7/vnn53l/kHfEImJRJMeijz/+2KpQoYK1aNEi69SpU9aXX35pNWrUyLrnnnuyfS70c+r7mXnzzTdNuS4ul8t8ruy/O3Xq5LXuk08+aXXu3LlIPnMIP2JjeGOjJ415eiyHDh3q9/Hrr7/emjFjRo7byMjIMO/nF1984bXdcuXK+d33YM2ePdvsm2fM0fdej6cea415un++/vWvf1l9+/bNVq7b+vbbb60yZcqY9zIhIcH8++KLL+Z7H1H4iBecS+VE63vZZZdZbdu2tU6ePJnt8Xnz5plzkEDnT8HS90yvqbp16+b38QEDBlgjR47MdTutWrWy3nrrLa/Pp+6fHpP8+uqrr8xnvGPHjl7XgPqe6PZfffVVc93o6/XXX7euvPLKbOX6nnzwwQfmelH3rVSpUlZcXJz10EMP5XnfSGAFcObMGWvp0qXWE088YT681apVMwfdtn37duuGG24wX6TrrrvOfJk8v2S+dFv6IQj0QfrHP/7h94cxkG3btlk1a9a0rr76avNjrIEpJSXFfMn0ouKll16yGjRoYN133325buvEiRNm33bs2OH3cd1OMIFOj5X+GBw5ciTgOtdcc43Vvn17K6/69+9vNW7c2EpLS/P7uJbr4/oDYLvggguyXdAEklOge+yxx/KUnLnoooust99+2+si8LXXXst20ej5ebLt37/f70WbL/1RDBT0czoZbNOmjQlyderUsVJTU7Oto4FoyZIluW5L93/BggXuv0eMGGHde++9edofBIdYlIVYFPmxSD/DesHgaf369eYk2PN9/+233/xeHGgCTo9RZmamu0z/P2bMGKtr165e6z711FN+E1iF8ZlD0SM2Ois2eurevbs519Bkk7/jqQmi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QawKLWIVEDmxigSWB7vJqAYughcQejTLDg1iFVC4iFWhQawCChexKjSIVUDkxCo6TQMAAAAAAMDRSGABAAAAAADA0UhgAQAAAAAAwNFIYAEAAAAAAMDRSGABAAAAAADA0UhgAQAAAAAAwNFIYAEAAAAAAMDRSGABAAAAAADA0UhgRZgvv/xSevbsKdWqVZNy5crJJZdcIp999pnXOlu3bpV77rlHGjZsKOXLl5cWLVrIrFmzvNZZvHixdOnSRSpVqiRJSUnSoUMH+f7774u4NgAAJ+jVq5f5LfBdEhISZNWqVWadzMxMeeyxx+Sss84yvy36G7Jr1y6v7Vx33XXmt8l3OxMnTgxTzQBEE2IVABRvJLAizNChQ+WGG26QHTt2yKFDh+TBBx+UHj16yLZt29zrPP3009K0aVP56quv5OjRozJ9+nSz3vz5883jqamp8s9//lPuvPNO+e233+T333+Xm2++Wa6//no5fPhwGGsHAAiHd9991/xeeC7ffvutucC78MILzTqPPPKIrF27VjZs2CAHDx40Nz70IlB/U2xpaWny2muvZduW/uYAQEERqwCgeCOBFWG0tVW/fv2kTJkyUqJECenevbvccsstsmzZMvc6L730ktx7771SpUoVcblcppXWAw884E5gxcfHy/r1681z9f+lSpUyLbZatmxpWngBAPDcc89J//79TcuGvXv3ytSpU+Wtt96SqlWrmt+f+++/X84991x59dVXw72rAIoxYhUAFB8ksCJM2bJls5WlpKSYhJYtNjY22zr79+83d6dUTEyMlC5dOtftAACKp2PHjsnbb78tgwcPNn8vWrRIrr76atPFxpN2aV+wYEGY9hJAcUesAoDihQRWBNNm0ZMnTzatqfSHOadWW3rX6b777sv2mGVZsm/fPhk5cqRprdW+fftC3msAgNO98sor0rlzZ6lRo4b5e/PmzdKoUaNs69WvX9885umjjz4yvyUVK1Y0YzFqF3a9QQIAoUasAoDihQRWBNJm0NqaSgdy137+2v1PuwH68+KLL0rv3r3l/fffN8+znT592tyd0u3UqlVLZsyYYbajrbMAAMVXRkaG6YLzj3/8w1124sQJqVChQrZ19cIvOTnZ/beOQWM//48//jAThuj4NHfccUeR7T+A4oFYBQDFT1y4dwB5p7MMKv3h1btJ2rJq06ZNZrB2m/5I63gAOkj7mjVrTJLKU8mSJc1glSo9Pd38aN91113yyy+/yIgRI4q4RgAAp9DxEs855xxp1aqVV/d1+zfDk5YlJia6/37mmWe8HteWEDrocvXq1c0NFX8XlgCQH8QqACh+aG4TwXSsK51t8IUXXjA/ujadSVAHbtcf408//TRb8spXXFycXHTRRTJhwgSv7QAAih/tmu7ZokHp78n27duzrasz4DZu3DjH7emEItriV7urA0CoEKsAoPghgRUFdMaV8uXLu/8eOnSomZnwsccey1OXQN/tAACKF22xq5N+dO3a1au8U6dOZryY48ePe5XPmzdPunXrluM2dSp7nbJex6ABgFAgVgFA8UQCK8LoD/WHH34oqamppuuftrDSroJjxoxxdx1cvny5GZQ9J5dddpmsWLHCbEN/rHWb+pxRo0YVUU0AAE5s0aA3QXxvftStW1duv/126devn2nlq78bkyZNki1btsjdd9/tXq9Pnz5mUGW9eNTfF51E5Oabb5bx48cHHKsRAPKKWAUAxRMJrAijP9avvfaa6RZYtWpVk3CaNm2aGb9K/frrr+aOlPbd13EAPBfProS6nSeffFIqV64sNWvWNINYLly4UK677row1g4AEC579uyRTz75JOAgxs8995zpgqNd1/W3Y+XKlfLxxx97XewNGDDAbENn9NIWvQ888IC5ILz33nuLsCYAohmxCgCKL5dlWVa4d8Ip9C6M/ogdO3bMzM4HIDQi/bvVq1cvWbp0abZync1TT4q1RWNmZqY8/vjj8tJLL5lZkC6//HKTXD777LO9nqMTLugJ8vr1682JtU7bPWjQoGJ1PAGnivTvFrEKKB74boUWxxOInO8WLbAAIBc6uYHOYOS56MydGoh1Km71yCOPyNq1a80YGgcPHpQOHTqYFo3a3ddznDkdn0NbQGpA1wvKGTNmyMyZM8NYOwDRglgFAACiGS2wPJB9BwpHNH639MJOp+TWlgx6sdekSRPZtWuXmcHIpgPG6oXh4MGDzd8DBw40x+Hf//63ex29iNQLRe0SoTOLFtfjCThBNH63iFVA9OG7FVocTyByvltxIdkK8uXNNScl2vS5qEy4dwEodBqE3377bdPFRi1atEiuvvpqrwtC1bNnT3n99dfdF4Xz58/P1r2nVatW5uJy9erVcumllxZhLRCVFo+TqNR5dLj3ICIRq+BY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K1eWUaNGeZW98sorYdsfAMgN51YAwoHYAyDqEli//vqrlC1b1nTF0W44mqk/fPiweUxn/Nq1a5d88MEH0qhRI7nlllsKe58BIEcal3zpOA8A4BScWwEIB2IPgKhPYF155ZWmC449Jb265JJLzHT0F198saxatUpuu+02mTBhghw5ckT+/ve/F/Z+A0BAOuaVr9OnT4dlXwDAH86tAIQDsQdA1Cewfvnll4CP6aDI1113nfTp00cGDBggPXv2JNABCKt9+/bJnXfe6f5b7zIePHjQnJzZJ2sAEE6cWwEIB2IPgGI5C+GmTZukZs2asnHjRunfv78pq127tpw4cSKU+wcAeTZx4kT33UVtHq8tstq2bWsGdAcAp+LcCkA4EHsARHUCS4PZ3/72NzMo8qFDh6RKlSrux2jdACDcuFsIINJwbgUgHIg9ACJJnqPS77//Lh06dJC77rrL9JPWlg3awsFmT12fH1WrVjXdfDwHGUxISJCkpKRsi3YR8rR7927p1q2blC9f3txBGDt2rOkuBAAA4GSFeW4FAIEQewBEmqCi0rp160zXmw8//FDmzp0rjz/+uPTo0cM8pll6TTpp0kgDXn6SRidPnpSXX35ZDhw44FWu49bExsbK0aNHc32+Bt8HHnhA5s2bZ7ajfbc1iaULAACAkxT2uRUA+EPsARD1Caz7779fduzYYWaimDJlijvIqZYtW8qCBQtk4MCB8p///EfatGmTpx148cUXZdiwYQUKkFOnTpVWrVqZwQZVjRo1ZNasWdKgQQMZMmSIVKpUKd/bBhA5rrnmGpP01niiCXBd7P/7K9MZdnQ2HgAoaoV5bgUAgRB7AER9AkunU1Xff/+9ydK/9dZb8t5775lE0d13322mXl28eLFs2LBBPv744zztgAZIXVR+B1ieP3++jBgxIlt3RB20edmyZdK7d+98bRdAZLnvvvukZMmSEh8fbwZx15hiL/4SWOeee264dxlAMVWY51YAEAixB0Aky1PH5hYtWsj7779vuvtddtllsnz5cqlTp45899138sUXX0izZs3M36GkF5qjR482r6tdA7VV1ciRI814V7bNmzdLo0aNsj23fv365rFATp8+bRbb8ePHzb/a/1sXe/BCXXQ/PFuJ2eXavFYvhHMr11YhehFtb9ewMjyGIfNtgRag3BWrfSsDlGuZFUS5S8QVk0N5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gNNEzRhYqmHDhrJkyZJw74ajlCxZUh599FHzL5yP96t4IFb5x+c/cvBeFQ/EKv/4/EcO3isUZ3z+IwfvVTEcAwsAAAAAAADRKWq6EAIAAAAAACA6kcACAAAAAACAo5HAimI63fXgwYOlZs2akpiYKC1btpSXX3453LsFDwcOHJDq1avLokWLsj02dOhQadeunWRkZIRl34CiQqxyPmIVQKyKBMQqgFgVCYhV+UcCK0rt27dPLrroIilVqpR89913cvz4cXnllVfkpZdekrvvvjvcu4c/ValSxbwvAwYMkMOHD7vLP//8c3njjTfkrbfektjY2LDuI1CYiFWRgViF4o5YFRmIVSjuiFWRgViVfwziHqVuuOEGOe+88+SZZ57xKj927JjJwj/xxBPSu3fvsO0fvN1zzz2SnJwss2bNklOnTknz5s1l9OjR0rdv33DvGlCoiFWRhViF4opYFVmIVSiuiFWRhViVdySwotBPP/0kF198scnAa7NRX6+99ppMmzZN1q1bF5b9Q3YnT56UCy64QCZMmCArVqyQ33//XebMmRPu3QIKFbEq8hCrUBwRqyIPsQrFEbEq8hCr8o4EVhTSJqLz5s2Tjz76yO/jGtRq1aplvjAJCQlFvn/wb82aNdKlSxfT5Pf777+XChUqhHuXgEJFrIpMxCoUN8SqyESsQnFDrIpMxKq8YQysKB24r2rVqjn2udW85ZEjR4p0v5AzHWjxzJkz5r3zd9cEiDbEqshErEJxQ6yKTMQqFDfEqshErMobElhRSLO2noPB+QtuLpeL7K6D6I+J9nUePny4VKpUSR599NFw7xJQ6IhVkYdYheKIWBV5iFUojohVkYdYlXcksKLQZZddJl9//bWkpKT4fXzZsmXSqlUrmo46iA60eOLECRO8dEaKF198Ub744otw7xZQqIhVkYdYheKIWBV5iFUojohVkYdYlQ86BhaizzXXXGONHj06W/nRo0etunXrWrNmzQrLfiG77777zipXrpz1008/uctefvll65xzzjHvFxDNiFWRg1iF4oxYFTmIVSjOiFWRg1iVPwziHqV0kL4rrrhCevXqJcOGDZOkpCRZvXq1DBo0yMxOodldhF9qaqq0bt3aNB198MEHvR67/vrrTVPS2bNnh23/gMJGrIoMxCoUd8SqyECsQnFHrIoMxKr8owthFA8G980338ixY8ekadOmZkC4v//97zJ48GACl4Noc9Fy5cqZHxhf2oz0P//5j7z11lth2TegKBCrIgOxCsUdsSoyEKtQ3BGrIgOxKv9ogQUAAAAAAABHowUWAAAAAAAAHI0EFgAAAAAAAByNBBYAAAAAAAAcjQQWAAAAAAAAHI0EFgAAAAAAAByNBBYAAAAAAAAcjQQWAAAAAAAAHI0EFhACaWlp4d4FAAgK8QqIbikpKWJZVrh3AwByRbxCXpHAgnHw4EEZPHiw1KxZUxITE6Vly5by8ssv+133xx9/lF69ekm1atWkTJkycu6558rDDz8sBw4ckM8++0xiY2OlbNmyZilXrpycffbZcs8998gff/yR4z6cOXPGb3lmZqacPn3a/P/aa6+Vr776yu963333nQwbNky6dOkiV111ldx6663y6quvysmTJyVURowYIePHj89W/u9//1smTJjg9zljxowJ+BiAvCNeBYd4BUSHdu3ayZo1a7KVn3POObJz585s5bfccou0adNG2rdvL9dff7107NjRxCONNZdccok0a9ZMXnrppaBff+XKlWZbvk6dOiUxMTGSkZHhVe57Map/e5bt3r1bateuHfTrA4gcxCsUtrhCfwU43r59++Syyy6Tm266yVxUValSRdavX28u4lavXi2vvPKKe93//Oc/ctttt8m//vUvc8FYunRp8xy94HnhhRdMwGjSpIls2rTJ64t///33S48ePeSLL74IuB/33Xef2VbJkiXNRaUGmfT0dJOZ12A2duxYU6aP+Zo4caLMnj3brPPQQw+Zi9odO3aYC8ILLrhAPv/8c3MBmxu9oB09erS5QL7iiivMdnVbnnQffLlcLhNcFy9ebB7XvzVA6rJr1y4ZPnx4rq8NIHfEqyzEK6B40Pig31NfcXFxJvnu6//+7//Mvx988IGJDZUrVzZ/60Vl1apVpU6dOnl6/e+//95vLNH4ZsdA23//+19p0aKFXHrppeY5mtTfvn273H777Sbm2fvtrz4AIh/xCoXOQrHXsWNH64EHHshWfvToUatOnTrWrFmzzN/79u2zkpKSrIULF/rdzu+//259+umn1vnnn5/tsYMHD2oq2zp58mSO+7JkyRLrnnvucf997rnnWjt27HD/ff3111tr1671es6BAwesihUrmtfwZ+TIkdY//vGPHF/Xrl+9evWsjRs3Wqmpqdag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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ocr_condition = (\n", + " (image_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"]==\"X\") &\n", + " (image_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"]==\"X\") &\n", + " (image_df[\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"]==\"X\")\n", + ")\n", + "\n", + "##### ์ „์ฒด\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = image_df[image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"][\"OCR ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ „์ฒด ์ƒํ’ˆ ๊ธฐ์ค€ OCR ํ•„์š” ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & ocr_condition][\"OCR ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"๊ฐœ๋ณ„ ์ด๋ฏธ์ง€ ๊ธฐ์ค€ OCR ํ•„์š” ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & ocr_condition][\"์ƒํ’ˆ ์„ค๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ƒํ’ˆ ์„ค๋ช…์ด ํฌํ•จ๋œ ์ด๋ฏธ์ง€ ๋น„์œจ\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & ocr_condition & (image_df[\"OCR ํ•„์š” ์—ฌ๋ถ€\"]==\"O\")][\"์ƒํ’ˆ ์„ค๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=\"lightgray\")\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"OCR ํ•„์š” ์ด๋ฏธ์ง€ ์ค‘ ์„ค๋ช… ํฌํ•จ ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "##### ์ˆœ์„œ ์œ ์ง€ O\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"OCR ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, OCR ํ•„์š” ์ƒํ’ˆ\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & ocr_condition][\"OCR ํ•„์š” ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, OCR ํ•„์š” ์ด๋ฏธ์ง€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & ocr_condition][\"์ƒํ’ˆ ์„ค๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ์ƒํ’ˆ ์„ค๋ช…\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & ocr_condition & (image_df[\"OCR ํ•„์š” ์—ฌ๋ถ€\"]==\"O\")][\"์ƒํ’ˆ ์„ค๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=\"lightgray\")\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, OCR O, ์ƒํ’ˆ ์„ค๋ช…\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "# plt.figure(figsize=(12, 6))\n", + "\n", + "# plt.subplot(1, 2, 1)\n", + "# bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & (image_df[\"OCR ํ•„์š” ์—ฌ๋ถ€\"]==\"O\")][\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "# for bar in bars.patches:\n", + "# bars.annotate(f\"{bar.get_height()}\",\n", + "# (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + "# xytext=(0, 0),\n", + "# textcoords=\"offset points\",\n", + "# ha=\"center\",\n", + "# va=\"bottom\")\n", + "# plt.title(\"OCR์ด ํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ์ค‘ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ๊ฐœ์ˆ˜\")\n", + "# plt.xticks(rotation=0, ha=\"center\")\n", + "# plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "# plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "# plt.subplot(1, 2, 2)\n", + "# bars = image_df[(image_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (image_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & (image_df[\"OCR ํ•„์š” ์—ฌ๋ถ€\"]==\"O\")][\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "# for bar in bars.patches:\n", + "# bars.annotate(f\"{bar.get_height()}\",\n", + "# (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + "# xytext=(0, 0),\n", + "# textcoords=\"offset points\",\n", + "# ha=\"center\",\n", + "# va=\"bottom\")\n", + "# plt.title(\"OCR์ด ํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ์ค‘ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ๊ฐœ์ˆ˜\")\n", + "# plt.xticks(rotation=0, ha=\"center\")\n", + "# plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "# plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "# plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€: O, X & ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\n", + "- ์ƒํ’ˆ๋ณ„ ์ œ๊ณต ์—ฌ๋ถ€ ํ™•์ธ\n", + "- ์ˆœ์„œ ์œ ์ง€ ํ™•์ธ" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABLIAAAJOCAYAAACjnC6hAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAw1dJREFUeJzs3Ql8VNX5//EnCSHsqwoiuLCJCyDuaOv2Q3+IIFXqX8UqtmqtRcGlVeqCdalUq1IVFbdSq1BFLSI/qqioVFBBqBZUcCmggBvKDgmBMP/X9+AZ7kxmkknIZOZOPu/Xa8Sc3Jnce2fumXOee85z8iKRSMQAAAAAAACALJef6R0AAAAAAAAAUkEgCwAAAAAAAKFAIAsAAAAAAAChQCALAAAAAAAAoUAgCwAAAAAAAKFAIAsAAAAAAAChQCALAAAAAAAAoUAgK8tt27Yt5v8jkUit/F39nY0bN9ba38tWdf344xUXF2d6FwAAqFG59F2v7+ktW7ZYXZdL7+nOKi0ttbKyskzvBtKoLn7e6+IxIxaBrFrw4YcfWuvWra2kpKTKz/2f//kf+/3vf+/+v3nz5jZp0qQa26/XXnvN7dfWrVvL/e7777+3pk2bWoMGDaxVq1a2++67W/v27d1D/7/rrru6/WnYsKHVq1fPvvnmm5S/TOODIf/85z/d62ZjhXTMMcfYH//4xxp/3T59+thdd91l2eazzz6zli1b2uLFixP+fr/99rP/+7//S/r8m2++2c4444w07iGqY2evrfXr19vmzZszug/ZLJePDXXPp59+am+//XaNv+69995rt956a5W/k6688ko7+OCDbbfddnNtDj323HNP69+/v40fPz7mhl91tWnTxp588kkLixNOOMH+9Kc/Jfzd1Vdf7c5RkyZNXFttjz32cG2sdu3aWdu2bV2bTr8rKiqyX//61yn/zXXr1pWr64466ih74IEHLNtMnz7dGjduXCOfjaB//etf7vzV9OvWhCFDhtjQoUMT/m7ChAl2xBFHVPj8goICW7BggeUC6rC6YeTIkda3b98af91bbrnFTj31VMtG//nPf1x9vnr16phyBarT1RZV/OK+++5z51p/239/KIageuWGG26wb7/9tsLXCA7G0f8n+sz/9re/tZ/97GdV2jcCWTuhojteweCQ3mx94BQUShbcUSdRz4kPduXl5UVfS//fqFGjKu3jM888Yz169Ej4OwWg/CPeLrvs4j5k2q9Vq1bZV199ZcuXL3cP/f/KlStt7dq1tmnTJtuwYYOrnOPts88+9tJLL8WUvfHGG648qH79+u7Y9EiFLgSdk2QXrPZbv9f7kyhIl4wqgfjtCwsL3fuXimHDhrn3uEWLFq7xqH/10AWv900j3IJUnsjEiRPt73//e9K/8+WXX9qll15qn3/+udU07f+aNWtcAzCRZJ+XIAVAkT3UMNU1tjOfFwUoTzzxxFprZBHwzu6At6hRc/LJJ5crr0qdW1X67rn++uutd+/erkOuelUdAnXQ9fl88MEH3WenIsFRCckafnr9sWPHWl11++2328CBA6v13KlTp5ZrYAe/uz766KOUX+vdd9+1Xr16uXaIPm8ff/yxa3Po9V9//XW3j6qbzj333ITPTzaK3be1gsF5fa8la6Mlou/JESNGWJcuXdzz9BlUA7wqx1eZnj172tNPP53098naEDpXOka1zdRWW7FihWu76fx//fXXrk2n3+nx5z//udzzx40b5wJU8dSJeeihh2LK8vPzU24jifYrWadd75WuSbXdKruO45+n5wTfa7Xd9ND+VUY3brWt2i7qmOmhG3rNmjVzbaHf/e535Y430evqvKpjrfOczCOPPOLqqXTQMSQ7t6m03XT+dIM6F1CHZbYOi78e44+pOte5nhff765KH+25555zbWFd1+qj6RpXH03XvdoSL774YnRb9UeT9YPmzp1rt912W4V/SwGZV1991VKl44ofManj9edHdbjeo4ULF7p98z8HXXDBBa5e0udAx6nfJ3vouFOl/Tr++ONdwFXBcn2m9dlRG33RokV24403usCxYg3Lli1L+jr333+/O6c67/ruuueeexIG06sa1CWQtRM6duzoGtG6CPSm+IcuKl1cQRUFaRTh1wdLz9HrBelD6V9L/683uSqWLFmS9MsrlS82UcdBX85Bo0ePtj/84Q/uuLTviY5P+xp/ofm/qYpcr6EP8vPPP1/uuCsyb968aAPFv57+lg+G6f/1e13IugsST++Pf6/8edfz9Do/+clPyu1vqudcDUJ9segCf+edd1ygTw0kjWZJFBxK9rr6Ep0yZUrSv6MvLlUIVR3hpwDZAQcc4I65a9eu9uijjybdNtnnVV9Ml1xyiR100EF2yCGH2GGHHWaHHnqo+/nAAw+0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Zdddd507vrffftu9vh75+fnu36+//jq63fTp093nslmzZpFdd901sueee7r3Tu/j7rvvHtljjz3cz3ofW7duHWncuHGksLDQvc4rr7xS5XODyq1atcqd3w8//LDc74444oiYOuSbb75x2y5ZsiRmu/Hjx7vrL96NN94YGThwYEzZ6NGjI6ecckrCffn222/d69x1113u52OPPTZy0kknlasPunbtGnnmmWci1fX+++9HRowYkfL2paWlkYkTJ0bmzp0b+fzzzyObNm0qt83LL7/sPreVWbNmTeSAAw6IXH/99Ql/P2DAgMhjjz1W6evovfjjH//oXi+R7777LrJhw4boz0ceeWTkiSeeSLjtueee697XvLw8d73pGvXXcfDxn//8J1IVl156aeS4445zf1f19urVq6O/e/rppyP777+/+//777/fvc/p9vrrryc8rkQPX3/5R7D+Ud2perBLly7uO3Xs2LHue0f12osvvhjzN4855pjImDFjIrlO14baHbo+Vq5cGfn+++/dZ3PKlCnuc5VM8PtHbRh9BwSvDdU1Oq+jRo2Ked4VV1zhvm8ro/dK9Yd/3Hbbbe49CZZ99dVX7j1esWJFwv0Kfsf/7Gc/i5YtX7480qFDh8hpp50Wc63pc6H6ojLa7ne/+12F27zwwgtu37SP6fLxxx+79ytVV111VeSCCy5I+Du1KfSId9RRR0VatmwZadOmTWTvvfdO2H5TG2Dx4sWRmqS/+a9//avCbe68807X3tBnOJHZs2e7z2VNUx2erF2jz62+d4J69+7tPi/Btluic53Mv//970iDBg1i3mu1xVWmY/zf//3faH2na/ZXv/pVzPNVlzdq1Mid03bt2rn3zb9/On/6f72Pbdu2ddesXregoCDyox/9KBIG1GHhrMPULqlfv36FfRm12c4888xIz549k9Z16oefc845Nb5/alu/9957CX+n6zfYvlXfTOdKfbXgdZ6sX5mIPr/qX6nvKpdccolra6mfLvqM6G+o/pk/f767RpP55z//Gbnwwgtdm3W33XZzfXC1v/v27Ru577773HWSquDnVZ877cNnn30WU65+pI9T+POT6Nj/+9//unal2lbqf+h14ukaPP300yNVwYisatIdMz00XE53qRVVDI6MCE658HfI4ynJuZKf6S6QhjXrObrjr8S4ytmiUQo+IaP4pHKpUnRZU1Z0h0932f3der2GIriK9GpUWTI+R5eP+PvocjD67Yc9+vxe8TSf1ucx8Xd34u/yaLhnZcvTVpWi68kSCetOpoZSKlm2hjPqDmGyO08+AXZV6Fg0RFl3R3VnPxg913lXone9x4mmhUn8efQj4oKrhVWV3meNtFMuDX2uNHpCU2x0R0TTFfwIQN3l034F7yRoBJyfBhDPr/4SjLzrc6Pt9a+SR6Pm6XOklUQ0BF75fTxNldPdad0N9PxnL77u8KNj9Bz/mdN7phFMqd5J0p1q5d7TqBaNxhHd2VfdqCnOGuHi8wAG67J4urOoulCfdY3o8aNJgwlptU9VmRqh16psVI3uYiWaJpjoGHWHTKN2EvE5ZSqjO3i6M5WMHzruqf5OtgCD3nvlbvHfNbqTrNERGmmhY/fnripTHjUSS3WjRhPrLqWGfWsUnN5Hf5zB76NknxPtgz4HGs2g0Wf6LtJ+aGSJ8kWqDtJQ+FRGCWg0V3AahpKOKj+WpnsEacSERrn53B6+TvNUb06ePNklqtb3g74Hjj/+ePeexk+zqMpojjBLNn1L9XZFqQX8Z0p3VzVyQSMfNVrA0whHfbfoPdbIGz8yIdU2THx7wo82DJYlWr03+FnXFDyN8tMIJeVo89S20h1vXdMHHXSQOwbddfY5Pyqj0fa6RjQyMVFuUNF3q743E+U2SpXyRGm6q+7Q++vO5yRRnaW6TXmzktEIAZ2PYI5EX5f6UVr6/+A2iUbaSjDfSpDfn5pc4VN36jV6LFn7TXfr1Z7RYg96HzXtr6babqIROBqpo+8GP0Jd50qfPY0k0LSXZCODdX7iR0jrZz9VrDptN+Xc1fepRuBoJoKuTf195cNU7rRgjiyNXImvk5MtpqSkyhr1ozZqcEEYfW6SzdbIRtRh2VuHVUTfwT7/UyIvvviiGxGna07HmixHXXWuc7VP1Nf2q1z6FQZ1/jSaVXWK+jbJVi2MT8fir/nqXudqy6jtpvPt6xa163V9673Sd0FwRFZFba8hQ4a4WQMavaY2udIHqQ2udr3qNE0xVN2q0V/qQ1Qm+Hn1x+lHmwYFjzlZ3aG2rPqGSqqv6eWqezTNV6+ra0x1ndpkGnVYFQSydpIuAjWENTUiGb1JujCCiTNFX0BKEK/Ogn/j9UWkD4TvvAQrzWAnojK6sHVRqIOpzkR8MjcFW7RssjpnqlAS5YhR3gAFmfRcv9+qVNSx0OurMlCQSkMItRJOIhUlqPcJ7YOdlMqOSdvGT5lMRMOE/VQVH0hUha0KQdOeNMxVF3R8XoWdrSTVCFCjQxei/lZ8EmmtzqD3Q8FLvf+prBxREx0qHac6vnqv9JnTvHRV5H6ln/gv1FQDGYkqLL+CDtJLgVgFJzW9QEEgTSXTvH+tthQclh5cmTTIJ3vUtAq9j/pi8l+QGuoblKjeqclGFgHvzAe8FUxU51j5efyKh5rCoEC3vgvUKEolkKUGkxpIqm9V1+r1NIVI+6sbKlpdSkPKdT4VeKos0Wh849//f/zxx0+FSfa9o/OqqRr6/lNQS/ukDqumYulcq/5WYzJ+mlEuU742fZ/7RQxSzZuoqbFPP/10wu9R1SE6v8GpI/FTIlKVaF/86yT7nOszqASyqiPj6ftPU0wUJPJTJ1LtBCqIosCuPtsKNMX/feVYUgDIJ+3115E+7wrqpkJTetWJ0/7r3AY/63qfdF6HDx/u6q9kq50pOKvPtNo6/lrQ+VcbTu0oTUvW9KGK3o+KAlS69pPd4EpE2wan+lbUdvMrymrf/GJCqo/VqVPnU1NU1BGraNpLdepk5SjTe6pOvNrGwU6+zplW2NL3gW4OK71IKoIrj1eXPg+6RrVCmF5L15barxIfrN+Ztpue7xNGhw11WHbUYeoDpZKjT9e5b3v5RcP0udPgEF3nypOnv6d0PRW9VnWuc7WXVacqFca+++4bU88psKIgi9oA6t9X1Lf3/N+v7nWutrtu7v3pT3+KvobOhU+RI/GBLP938wOfK6UEUrtGuU3jb9CqPlU8QA8FtnS9KPF9VSS7nlKdhqzpg7rRqIEPOq8Kkuo7Qe+92mRqG+pGr1LdKEVJqghk7aRUvpj1gUp08etDm4jPR+IrheqMyFIHVR9q3Y2Jv8sv6rzqg6QvSH0pJ5rLrQ+m7srrw5WMoqcV0d9XQjd9YH0UV//6pYh9ZyiVfCS6E9e9e3f3fFWUFZ17dU6Uk0UVtv6WotS6y6ZcVeo8qrOfyl3ERPkNKqK57aoIlZQw0YWtqLM6/wpy6bwHA1n6jOh4FKjTvvkRM6rQ9b7r/dTvfV4ZnT91wHQu/CiEimiETKIVP4JqIpCF2qHPshpgmlOuhr06LvF3FSsakaWcC34UVLz4z3yi0VQ12cgi4J35gLdGYypgFVxdUDdgdGfUj1hKJZClhpSCWeoAxI+4UtBKAU499PnRiDMlXq3NxpS+8/S9oM6q/ra+H/XZU12qPILKT6j3Reffr+Kb6xTUCOZH9NdbZedU562iayN+tEx1R8kkqjcqawvpM5uobvLUUfAB26p0AjXSQ9ekbgLp9dWOUmdInx0lX1eHT/WygvieOoVKFq4OS7LlyYN0zamNojo+nuo11Qe6eag6KlkgS+9bsvpZdLOhsnpNv1ewTHV4MHmvz8uk99IHnCqjzqmCTz5pdrJV2/Taqh/V2fLtX3UoNUJGgf2KRqnuTNtN1CbTKLdE9a2+JxXc0sJOCoYHrw2NONWNCR2b6jzf2dQ5UntQv1P71Y8sVttNQRf9Tq+lc1gR1VEa4VqZnQ1khRl1WHbUYcrhp/6XH1mfaEVl0WdfNAJK17wGUyjQof6yghmq+1JZKbS617n6proJnOjcaISe2tQKmgcDWdo/BVl0XD6/qs+X5UdW6VoO9tF0bMpHpjZPMuq/JerDqb3k3//4HFmJAll5KS7spPrEn/+qSPbZSjUuoT6B8qXpeyv+c6z3Xw+1Q3WTnEBWLfJf7Pog64Otn/3KGH56gv/y8snTq0JfdtUJZKljpGlkGharSkFflj6ppvZPgS51oDTUMNkKY6l0Cir7MtSXhPbFJ3JLRBd7okR58XRXRI0BP+InuMSo5ysWv3qP/9knONQFU5UkvqlOGfL0ZaDRFAqcqdGlwFvw7pamcWl6i0ZhxE8xUsWtDqzo2HxASw9VPAoa+oCCPy491OhS5L4m+EZQKl+GUpNTClB1qaxElGxEVkV3LOPL/RdzuhpZBLwzH/AOrn4WFPzbwUBWsul3foh+Zd8f+vxkojGlz5rutMdfN/pu1h1iPXTOFdCqK4EsXW/6DvYpCHQDSw1Kv1Kob5CnurpkMtUdzZDoPa/pqZ+pdgJ9W0QjTTWaXtepph/re191mILj8XfDVb8oEJFKx0z02dSNBp9iQoEbPzpInSKNDNKN0EQL1HiVXX+pBDK0jerBZEmr/UiKVNqKChorCOSTIwe/f4JJuP0NhWD7TTdepbLA28603UT1gqZb6b1Ue0sjNP2x6Th13vV73WAIHrOmI2rUruiY/GIXftqm2tvaJr7tpv3TlPBUpvikItH3dF1pu1GHZUcdplFcfhS1HyUerGv859730fx1Hhx1qn5ruq9z3azSzQBN3wumFtDnRUnWdaNLM6SCFNRSgM9fP351QN9H88EX3+cPXueJFuyqTt8sOCIr/rwdeOCBbjqk6ifti+pL1Z367tC1oUClph1qpJtGyldVss9WqudfdaquQd3U0OwRfcb0edLr6rpVoEvfN4mS+leEQNZO0huoOwHqtPlRBT4C7S9g/yWtqTGa2lUVygXiV7bSa/t8M5XRtgqW6O64pv3oC1h5B/SB0QdfHUYFt9RgV6cvEW2rCk0fNAXh9NCF6ysfXVAKvFTU2FdlpbtV6iT4L3h/PoLLgAaHpCajjluyaUDpkuqXQnAflV9GF6NGNqhzqS9Q33BTB1XnXY0XBRqDNHpF51fnOVOrxfjjTfWuXl3IIxN2yQJZ6WogV6eRRcA7HAHv4M2UZCOy1EhRI1BT0DV8XQ1F7ZfeC3XCdddSjUGNCEm0Gle6G1Nq6Ck4oO9A3SVVZ1XfT/ou0sgJ1c1q7Om7t67QdaCgqc6FXynX88uJ66FARCpTLZLR56U6322JVmdNNtK0uvQ6qmNSpXaROgR6VEYjGJT/I5VRoj6QpREQCqorFYA65BoJoHOnz6rqOH12Nb0wGb1vmvatNqNvvwWD7r4ujb+rH6S/pyk2uo59hy04QtZPLVQdpRXfKpJsinS6VOf7yq+OptUQ1VZX29VPu1fbVB0v3bzR+QhSoE/vk85xJtMq+O+yuth2ow7Ljjqsspyj2XCdK7eoRp7ps6DBHD5Pkz4zOidqj2n6m1/F1VNKBD3UVqvtEY0a6aaRumpLaYSqJLrW//73v7sRTXoofYym7KndpfdN14ZvByYbwFIR/b1EI2kryn8bpNFYms6olB033XSTu6GrlCI+f6pufKvtWNEN8kTckg5VPhrEfBnoQvIdiVziOy2JEib6TqnvJO7s31Hl6xta2aSiRl4uUsRe0XzlywkuOVzRKA5NI9PIEmQn3WnTtIxE8+ZTpemK6txXJ/Dg6XOiOy0K3MTT6Bc/QmZnA96ZoKC0koPGD5muiIboK+CtwEmygLc6kfEBb+W1yVTA+4svvnCfJ+VZUONXwTbdRYunEWDqhCuPjKYmqbGi902dcNUrqmN0bPFTKlOh6VJqZKoRFKRzp85/RaNUPDVe1SDVZ1p1nu7C6nyqsaiGnjqqyW7w5CLfQA3T96muAwUb1SBWA3ln6bOqHESqK2uargVdswp21BZfnySqI/wogZ0NuvigVqIk55mW6lTjXKKAot73VEZb6IaC8h/qpkgu9F2ow3KvDktFXeujZaP77rvPfeYqmj6ZTgSyACCHqYGnQFCmE7jubCOLgDcqosCYgqT6jAEAACC3EcgCAAAAAABAKHALGQAAAAAAAKFAIAsAAAAAAAChQCALAAAAAAAAoVB+Obo6TAl7tfx206ZN69xqJ0AmKVWflsBt164dSbOToH4CMoc6qmLUT0DmUD9VjjoKyL36iUBWgCo4Lb8NIDOWLVtm7du3z/RuZCXqJyDzqKMSo34CMo/6KTnqKCD36icCWQGK0vsT3axZs0zvDlBnrFu3zjUw/DWI8qifgMyhjqoY9ROQOdRPlaOOAnKvfiKQFeCHmqqCo5IDah/DvZOjfgIyjzoqMeonIPOon5KjjgJyr35iIjUAAAAAAABCgUAWAAAAAAAAQiGjgaxZs2bZmWeeaW3atHHDPHv37m1vvPFG9Pf/+te/rFGjRtaiRYuYxy677FLutT744AM77rjj3PzLffbZxx544IFaPhoAAAAAAADkbCBr+PDhdvLJJ9vixYvt+++/t9/+9rc2aNAg++STT6JLpXbs2NHWrFkT8/juu+9iXmfFihXWr18/93pKKPbKK6/Yww8/bOPGjcvQkQEAAAAAACCnkr1r9FWTJk2iP59++un28ssv27Rp06xr164pv86tt95qgwcPttNOO8393LlzZxfEUnDrvPPOs4KCgrTsPwAAAAAAAOrIiKxgEMsrLi62xo0bV+l1Jk2aZGeddVZMWa9evdw0w9mzZ+/0fgIAAAAAAKCOj8gK0nTBJ554wubNmxeT32rDhg1uyuCUKVNs/fr1tv/++9sf/vAH+9GPfuR+v3r1avvmm28SjuDq1KmTLVy40I466qiEf3Pz5s3u4WlaomzdutU9JD8/3z00zVEPz5eXlZVZJBKptFyjwrTspH/dYLlo+1TK69Wr5143WK7X1fbx+5isnGPimLLtmIL/DwAAAABA1gay9t13X/vqq69s48aN1qBBA7v99tvdv9KyZUsXoNLoqptuuskKCwvt2Weftb59+9rbb79t3bt3d4Gu+vXru6Tw8Vq1auWCX8mMGjXKvW689957LzoqbNddd3UBsSVLltjKlSuj27Rv3949lM9r7dq10XLl9Nptt91c8nmNLvO6devmEtXrtYOBgB49erj9nzt3bsw+HHrooVZaWmrz58+PlikwcNhhh7m/t2jRIvvPf/5jzzzzjHvNLVu2uHP1i1/8wg4++GC3ffPmzW2//fazL7/80pYvX+62u/TSS+25556zn/zkJzHH9N///tfGjBnj9lvPO/vss12+sto+Jq9hw4bWs2dPF+BUDjUv/pi8bH6fOKbKj0nbI7doMY97773XTSHX5/GAAw5wda4W5ZBvv/3W/V51uj4jWsTjggsusOuuu84FO71Nmza5nIdPPfWU+8yrrlf9pRsafG4ApKN+ko8//thGjx5t06dPd/XV3nvvbVdffbWdc8450W2mTp1qDz74oGuT6vtV35933XWX+14EgHTVT0Gql9T+/81vflPud7oBff/997uH2uTqPyjtzjXXXFMLRwKkWSRLbN26NbJgwYLIcccdF7n44osr3Payyy6LDBs2zP3/qlWrNPQksmnTpnLb9evXL/Loo48mfZ2SkpLI2rVro49ly5a51/r+++8jW7ZscY+ysjK3rf71ZcFy7Xcq5du2bXPlwTJfrkeq5eLLDz74YHd82vfS0tLIM888E2nVqlXkww8/dL/XPvh9X7lyZeSAAw6ING/ePDJ79uyYY1q6dGmkQ4cOkWeffda99qJFiyI9evSIPPLII7V+TP4R3PdUyrP5feKYKj+m1atXu2tPn2UkpnMTpnN0yCGHRMaNGxfZsGGDq5+ee+45Vz99/PHH7vfXXnutq8f/+9//up8/+eSTyBFHHBG55ZZbYl5n8uTJkZ///OeR+fPnu8/V119/HTnjjDMiAwcOzMhxoW4K2/VX23KtfpILLrggct9990W+/fZb99331ltvRXbffffIP/7xD/f74uLiSLdu3dxzN2/e7H5+8MEHI23atHHtSKC2hO36y4QwnaNU6iffln733Xcje+yxR+RPf/pT0j7zj3/8Y9c3lM8++yxy66231spxAOm+9vL0H8siH330kZsKqNUJk7nvvvvsX//6lxuN5Ed5vPbaa26EVlCXLl3sr3/9qx199NEp/W1NLdQdfo06adasmWU7jUaLzzP2q1/9ykXuL7vssphyjbDSSLYbb7zRjYDQXUPvkksuccf9xz/+MVqm0TtKlq+REiTLR7qF7drLhFyrnxL9/p133rGhQ4e6KeaeRjnE10EaAbj77ru7kbwaVQikW9iuv9qWi+2nRHXPnXfe6UYr/+1vf3NT4ktKSsrNCFBbS/XYgAEDauFIgPBdf5kQpnOUSv2k49DoKs3I0UMzmuJHZL3++utupPuCBQuqnH8aCMO1l9Fk74msWLGi0ukir776qh100EHRn/v3728TJ06M2UYNDU0rPOKIIyxXpZosXw0uNciGDBmS8HVIlg+gtuunVOuvRIF05UVU51F52wCgqlKpf5LVPb4hrinQidJaVGfRIgCoSv2kvrL6uQqmn3vuuQlfR9OeFfiiPkKuymggS3ernn/+eXcRKhG1IscXXXSRjRw50v1eo66Ui+D99993c3x1F/7KK6+0Dz/80N3t8pRT5dFHH3W5CnxeA83/VXS6rnR0dG6Uy0EjGc4888xouXIRaaTVQw89lPB5qSTLB4B01E+evgNU/w8bNsyuvfbaCl9Ld3SUC/Cqq66KyaUFAOmonzzlq3nsscfKjXgXtVGVf0b1lxY7SZbLBgDSUT8l8tZbb1nv3r3d8w888EA3g+l//ud/Yka9A2GW0SiPViNUMrsLL7zQDdFWUmqtWKgpbaKk5ZouqE6LkvwqsbSCX7owlbza69y5s73wwgt2xRVXuJFFShqsxkSyEUi5pKJk+RqFpSi9krgrcX4iO5MsHwCqWz+JFttQA0t3GrXAwBlnnFFuiniQbmJoG03dueGGG2rpKADUxfopfmTDLbfc4lJa6HmeVr5u06aNa2/pddRuUpuLIDuA2qqfktEiFZpuqHaVBnuornr88cetT58+buZShw4d0rb/QM4HsnQh6VHR0MoRI0a4R2W0otrMmTOtrtHoM1EjSqOndKdQq9aNHTvWNboUiT/hhBMqPMfqQKojqUBhkPKUaXohANR0/STK2aeHv+uock0HVwNLHcIg5TtU8Eo3P0477bQMHA2AulQ/iW7maaaAOpRz5sxxOWmCioqKojldNbPg3//+t8tJs3Tp0pTargBQ3fqpMhqooMEhwZHuF198scsrPX78eOoohB63jHKEcjlo2KiWV9Uy9aJ/tWy9Rq/5xxdffGHHH3+8+39F6jVSSyPYPvvss3KvqVFwGiUHADVdP8VTPXT99ddbu3bt3LTyIDW2ND1aS9wTxAJQG/XTqlWr3M1ApV7Q1Of4IFY8pbI4/PDD3ciJZPUcANR0+6miUV177713ufL999/fBduBsCOQlWOCyfIXLVrk8snobqF/7Lnnnq5Bpv/fbbfd6nSyfADZtZiHRjQowB7cZvr06W5IvBb5qKwjCQA1VT8p/YWmMt98881VmiqYyqJFAFAV1alXBg0a5AJgyuEXNHfu3IS5kYGwIZAVYpUly08VyfIB1Hb9dNddd7kcWZqyI8uWLXOLe+ju4bHHHht9nUceecR1JFl1B0Bt1U+6kacgemWLT/zoRz9y03T0GkrToNfUc9SuAoBM9u8UjPcL5GhhL6WRufPOO+29996zn//852nbf6C2EMgKMVVQf/nLX9woBY2uUsNJyfKVn6EqfLL8UaNGuZxYSqSsVSHrQrJ8AJmpn84++2w3MlQdQdU7WklHw+D/+c9/xox+0LTnn/3sZy6fX/zj//7v/zJ4hABytX76/PPPXcdP6Rfi653gyFC9zm233eamRmtatBK9qz110kknZfDoAIRZTfXvdANQq62KUsUo2fubb77p0jckWwQMCJO8SPx4wzps3bp1btimotfNmjXL9O4AdQbXXuU4R0DmcP1VjPMDZA7XX+U4R0DuXXuMyAIAAAAAAEAoEMgCAAAAAABAKJDJO8P+Nmej5bLzDidBMxBW1E8AshX1E4BsRf0EpB8jsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAAABAKBLIAAAAAAAAQCgSyAAAAAAAAEAoEsgAAAAAANWLWrFl25plnWps2baxZs2bWu3dve+ONN2K22bZtm9188822xx57WPPmza1///72xRdflHutDz74wI477jhr2rSp7bPPPvbAAw/U4pEAyFYEsgAAAAAANWL48OF28skn2+LFi+3777+33/72tzZo0CD75JNPottcf/319u6779p7771n3333nfXp08dOOukkKykpiW6zYsUK69evn3u9devW2SuvvGIPP/ywjRs3LkNHBiBbEMgCAAAAANQIjb46//zzrXHjxlZYWGinn366nXHGGTZt2rRogGrMmDH2xBNP2G677ea2ufzyy23fffe1xx57LPo6t956qw0ePNhOO+00y8vLs86dO7sg1rXXXmtlZWUZPEIAmUYgCwAAAABQI5o0aVKurLi42AW2ZMqUKXbCCSdYixYtYrbRdMTJkydHf540aZKdddZZMdv06tXLTTOcPXt22vYfQPYjkAUAAAAAqHGaNjh69GibN2+eC1TJwoULrWvXruW27dSpk/udrF692r755ptKtwNQN9XL9A4AAAAAAHKHpgl+9dVXtnHjRmvQoIHdfvvt7l/ZsGGDtW3bttxzWrVqZevXr49uU79+fWvUqFGF2yWyefNm9/CUX0u2bt3qHpKfn+8eSjqvh+fLNXUxEolUWl5QUOCmPfrXdSJlgfEiO177h1dKXJ5XYOZeN1G5yiIplOeZ5eVXUB4/HTNZeb5ZXl7i8h/OY5DOgcRP96xXr547V8FynSttH3/ek5Wn9X2qYN85prwaOabg/9c0AlkAAAAAgBrz8ccfu3/VOdboqcsuu8ytQDh27Fg39XDNmjXlnqMyTRsUbVNaWuqmJDZs2DDpdomMGjXKbrrppnLlSizvpzfuuuuubmTXkiVLbOXKldFt2rdv7x5KTL927dpoeceOHV0+Lx2D9snr1q2bmyKp1/aBgEZryqy4eTeL5Bdao9ULYvZhU8vulrdtizVcuyhaFsnLt+KWPSx/63prsH5xtHxbQQMrad7N6pWutvobl0XLywqb2uamnayw5FsrLP46Wr61qJWVNt7T6m9abvU2r4qWb2nY1j2KNiy1gi07AoCljTvY1qLW1mDdp5ZftiPJfknTjratsJk1XPOh5bmg2Hb+mObOnRtzTIceeqh7r+bPnx8tU7DjsMMOc+dw0aIdx6r3smfPnm6knhYD8LRy5X777WdffvmlLV++PFqezvdJevTo4QKmHNPatByTtk+XvEgwrFfHKVqvk603UkvF1oa/zdlouey8w7d/WQDZdu2FDfVTzaN+QqqooypG/VTzqJ+Qa/XTRx99ZEcddZQLQt1///322muv2XPPPRezzfjx4+2vf/2rW53Qd461Xffu3WO269Kli9vu6KOPTnlEVocOHdwKiv4cpXNUzIR5m3J6RNbgQ7aPrAueA2H0Ese0La5cIytbtmyZlvqJEVkAAAAAgLTRSoV+dEa/fv1sxIgRLsAU7NwqsDVw4MDoz/3797eJEyfGBLI0mkTTCo844oikf6uoqMg94qnDrkeQ74DH853+VMtjXldBph3PSLKXCcoVPEpYniStdZXLC2qkPP4cVlSuwEei8mTnvarlO/U+VbOcY7KUyxNtU1NI9g4AAAAAqBEDBgyw559/3kpKStxokddff90uuugiGzlypPv9PvvsY+eee66df/75tmrVKjfd6e6773ZTmy688MLo61x33XX26KOP2tSpU6PTFc877zyXbytZJx1A3UAgCwAAIERmzZrlVv9q06aNG83Qu3dve+ONN2K20dD+m2++2fbYYw83CkIjG7744otyr6WcG8cdd5zLN6PO5QMPPFCLRwIgFw0fPtz+8pe/uHw/yu2jgJTqlgsuuCC6zT333ONy/Bx44IG2yy672IwZM9yUQp8QXjp37mwvvPCCy3mlOqpv3742dOhQGzJkSIaODEC2IJQNAAAQsk7ipZde6jqKSug6ZcoUGzRokL399tvRpeqvv/56W7BggUsCq/wUyklz0kkn2fvvvx/tKGqqj6b4qEP5k5/8xP773//aT3/6U5fk9ec//3mGjxJAWPXp08c9KlJYWGi33Xabe1REiahnzpxZw3sIIOwYkQUAABAiGn2lKTlafUudwdNPP93OOOMMmzZtWjRANWbMGHviiSfcaAhtc/nll9u+++5rjz32WPR1br31Vhs8eLCddtppLj+GRj+MGzfOrr322nLJYAEAALIFgSwAAIAQ0bL08bQkt19WXiO0TjjhBLcsd5CmI06ePDn686RJk+yss86K2aZXr15uCs/s2bPTtv8AAAA7g0AWAABASH333Xc2evRomzdvngtUycKFC6NTDIM6derkfierV6+2b775ptLtAAAAsg05sgAAAEJG0wS/+uor27hxo8t5pVW8fO6rDRs2WNu2bcs9p1WrVm7Zer+N8ms1atSowu0S2bx5s3t469atc/9qdTI9gktwK+m8Hp4v19TFSCRSabmWG9e0R/+6UdFtdrz2D6+UuFzLyLvnJCpXWSSF8rzty9onLY+fjpmsPF9rnScu/2Hfg8frl1yPn+6pVdt0roLlOlfaPv68JytP9/uUbN85ppo7JgCoiwhkAQAAhIyWoRd1jjV66rLLLnMrEI4dO9ZNPVyzZk2556hM0wZF22jJe01JVHL3ZNslohXEbrrppnLlSizvpzfuuuuubmTXkiVLbOXKldFttIqZHp988omtXbs2Wt6xY0eXz0vHoH3ytKqZpkjqtWMCAZEuFskvtEarF8Ts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PYJ8Bzye7/SnWh7/ui4QtP0ZSfYyQbl7TqLyJNOzqlxeUDPlVlD+eBOdgx8CH4nKk533qpbv9PtUjXKOqerlAAAAyA601AAggQEDBtjzzz9vJSUlbrTI66+/bhdddJGNHDnS/X6fffaxc889184//3xbtWqVm+509913u6lNF154YfR1rrvuOnv00Udt6tSp0emK5513nsu3layTDgAAAABIjEAWACQwfPhw+8tf/uLy4yi3jwJSDzzwgF1wwQXRbe655x6X4+fAAw+0XXbZxWbMmOGmFPqE8NK5c2d74YUXXM4r5cTq27evDR061IYMGZKhIwMAAACA8MpoIGvWrFluKfs2bdq4qTm9e/e2N954I2Yb5am4+eabbY899nBTejRN54svvij3Wkoge9xxx7mOokZKqMMJANXVp08fF4BSomiNuHrrrbfcdMKgwsJCu+2221zSaE0xnDx5squr4ikR9cyZM910QiWS1sguAAAAAEDIAlka8XDyySe71YSUwPi3v/2tDRo0yK125F1//fX27rvvuhWN1KFU5/Kkk05y032CeWvUwdTrqTOpEREPP/ywjRs3LkNHBgAAAAAAgJwKZGn0lfLLaCl5jWw4/fTT7YwzzrBp06ZFA1RjxoyxJ554wk3t0TaXX3657bvvvvbYY49FX+fWW2+1wYMH22mnneaSvWoqj4JY1157bbmVjQAAAAAAABBOGQ1kNWnSpFxZcXGxC2zJlClT7IQTTrAWLVrEbKPpiJrC402aNMnOOuusmG169erlphnOnj07bfsPAAAAAACA2pM1S2Zp2qBGXs2bNy+a32rhwoXWtWvXctt26tTJ/U5Wr15t33zzTYXbHXXUUQn/5ubNm93D07RE0QplegSX4VauLj08X64RX5FIpNJyLTmu0WL+daOi2+x47R9eKXG5lpJ3z0lUrrJICuV525e2T1oeP4otWXm+1jtPXP7DvgeP1y+7Hj9KTiu36VwFy3WutH38eU9Wnu73Kdm+c0w1c0zB/wcAAAAAIGsDWZom+NVXX9nGjRvdSl9akt6v+LVhwwZr27Ztuee0atXKJU3229SvX98aNWpU4XaJaBWxm266qVy58nH5UWG77rqrC4gpQfPKlSuj22glMz2Uz2vt2rXR8o4dO7ppkEo+r9FlnlY208gyvXZMICDSxSL5hdZo9YKYfdjUsrvlbdti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XBlTrlxcmmK9Zs2aSp/fp08fu/LKK+25555zr3Peeee5YJYeAOqulAJZS5cuTfo7JQI86aSTXKVy8cUX25lnnkkjDECt0x28X/ziFzGNJN39U2fRdx4BoLbRhgJQF9tPDz74oF111VU7NXpK+bt69erl6kfZfffdbfz48da5c2cbNmyYtW7dutqvDaCOrlr4wQcfuOGd8+fPt4suusiVdejQwTZs2FCT+wcAKbnzzjujox602o7uMB555JEucSkAZBPaUAByvf10ySWXuIdU97UmTZpkI0aMKDdNUfs3bdo0Gzx48E7tI4A6FshSQ+vss892iQCV92HXXXeN/o6RDwAygVEMAMKANhSAbJKp9pNGat1www0uP6CmDGqU1bXXXuvyYXnKIdi1a9dyz+3UqZP7XTKaGhmcHrlu3Tr3r4J0fiqln+6t/QiOGvPlCuppdFpl5ZoiqUBdzBTNSFkgFXX8iLQk5XkFGg6XpFxlkRTK88zy8iso135ZCuX5ij4mLk8wHVXnQHRugrQaps5VsFznStvHn/dk5Wl9nyrYd44pr0aOKZ357KocyPr666/tJz/5iV1wwQUut4NOnA7anxi/fCsAAABqpw2lUQofffSRW4HMJ1Pu1q1bwkTO2k4jwoLJlC+99FJ74403rHHjxm4ajzqYBNYApIMSvR999NHWqlUre/PNN61Zs2ZuhNX5559vEyZMsL59+0YD/y1btiz3fD1v/fr1SV9/1KhRCXNovffee66OE91EUEBsyZIlMTm82rdv7x6ffPKJrV27NlresWNHV89qRG1xcXG0XPWsktTrtX0goNGaMitu3s0i+YXWaPWCmH3Y1LK75W3bYg3XLoqWRfLyrbhlD8vfut4arF8cLd9W0MBKmnezeqWrrf7GZdHyssKmtrlpJyss+dYKi7+Olm8tamWljfe0+puWW73Nq6LlWxq2dY+iDUutYMuO81bauINtLWptDdZ9avllJdHykqYdbVthM2u45kPLc0Gx7fwxzZ07N+aYDj30UCstLXWjjD19rx122GHuHC5atCjmve/Zs6ebvrp48Y5jVTL//fbbz011Xb58ebQ8ne+T9OjRwy1uwDGtTcsxaft0yYsEw3pJ6CQo+vb888/bs88+a7feeqsNGjTI/U7/3nfffa5BpBOoExHWZaUVrdfJ1hupCrU2/G3ORstl5x2+/csC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "size_df = emart_df[[\"img-ID\", \"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\", \"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\"]]\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = size_df[size_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"][\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ „์ฒด ์ƒํ’ˆ๋ณ„ ํฌ๊ธฐ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "# ํ•œ ์ƒํ’ˆ ๋‚ด์—์„œ ํฌ๊ธฐ ์ •๋ณด๋ฅผ ๋‘ ๋ฒˆ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ??\n", + "plt.subplot(1, 4, 2)\n", + "bars = size_df[size_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\"][\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ด๋ฏธ์ง€๋ณ„ ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = size_df[(size_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (size_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{int(bar.get_height())}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ์ƒํ’ˆ๋ณ„ ํฌ๊ธฐ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = size_df[(size_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (size_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ํฌ๊ธฐ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ๋ณด๊ด€ ์ •๋ณด: ์•„์ด์ฝ˜, ๋ณด๊ด€ ๋ฐฉ๋ฒ• ๋ช…์‹œ, ๊ธ€ ๋‚ด์— ์–ธ๊ธ‰, ํฌ์žฅ์ง€์— ํฌํ•จ, ์„ฑ๋ถ„ ํ‘œ๊ธฐ, ์—†์Œ\n", + "- ์„ฑ๋ถ„ ํ‘œ๊ธฐ ์™ธ ๋ณ„๋„๋กœ ํ‘œ๊ธฐ๋œ ์ƒํ’ˆ์˜ ๋น„์œจ ํ™•์ธ\n", + "- ์ˆœ์„œ ์œ ์ง€ ํ™•์ธ" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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8hUASHfK43r16mWnnnqqzZkzJzKthBoI9XKQW265xb3FTeWkSy+91L2USA0FAFAdyKOAqkUwLENorh9NpPjoo4+6SqxoKNNnn31WYl29PU5dauOpVauWnXbaaa7HiPc9ADI/vxDNRaG3FSnveOutt6xNmzZRn2vatKmbdLW8+QoApBvNq6q3Zz/77LN2zz33JNUbvlOnTm46CQCoauRRQNUjGJZh9AZJvbFB9Ha31157zfUE8VNvEL1RMtnvAZCZYu9zzUdxxRVX2G9+85uEha4BAwbY1KlTo9L0tkn1KNN8FQCQ7rZt2+YmlZ41a5YbapSsN954w0455ZQq3TYAII8CqgfBsBrskksusX/+85/u7SCFhYWuJ8cNN9xgd999t/v98ccfb9dcc40bP64eHxre9NBDD9nKlSvt+uuvj3zPWWedZW+++ab7Dq2j79Qk+nfeeWcK9w5AdeYXCmapC77u/dIoX3j66aftlVdeiQy9vPbaa11vUvUsBYB0p7kQBw0aZCeccELc369bt841KL777rtukmo1Kv7ud7+z559/nrIRgCpHHgVUD4JhNZh6cfz5z392Q5latmzpMr/HHnvMrrvuusg6f/zjH93QJQ2J0vCmuXPnujHm/kmz9T3333+/+33r1q3d5PkvvfSSXXjhhSnaMwDVnV+oYKU3RWoopOYG8y/+4ZIdO3Z0+cO4cePcHGGapFXzjmlyVwCoCTTU+4knniiR12m57bbbXFno4osvtlGjRrk5eo477jhbuHChvf/++9auXbtUbz6ADEceBVSPUFjvaoWjqLqGDO3atcu9lQNA9eDeKxvHCEiddLv/VHTTlAfqpfmf//zHvQ36zDPPdD0D9PZXBbfVEKZJlWN9/PHHriLlWb9+vf3sZz+zt99+2+rXr2833nijjRkzplxvlE634wMESTref+RRAGrCvUfPMAAAgBpEhcpHHnnE9QpYu3atff755+7lF3379nVDnlUR1Ysy9JbX2MVfydy3b5/7jIbbaI6axYsX27x582zs2LEp3T8ANRt5FICaIKXBMI1zvvLKK93rYRUpVCapqL+fxkFrMudvfOMbLqqoyZuVocZavny5nXvuuW7YjubK0vAfAACATKPykKY9OP/88920B7m5uTZ69GiXrqEyydK0CD169HA9LTTn3zHHHGOTJ0+28ePHu4onAFQEeRSA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ggnhThbOyrF6O5ZFbcP+pidbqPig5e5aGUkLh7Isr2k3yyrcY3X3rI6kF2fXtfzGXaxWwQ6rve/wK9mLchragYYdLCf/K8vJ+zKSXlinmRXUP9Zq799gtQ5sj6QfzG3lljp711r2wcPHraB+Wyus09zq7v7UsooO9+DLb9jeinMaWe7OjyzkAmtfy2vcJbJPixYdfshqzpSCggJbunRpJE0P4V69erljuHLlyqhz3717d/dCBc2x4tELErp27epeoLBhw4ZIelWfp27durnJjhctWhR1ntinytknrV8RRx99tJ155pnurWyal0fb6QXcvOFGypcUbFMwMDbABwBVLVVlKABIhPITACgW4+9CkqBF84orrrCXX37Z/axKsgp0ekX42Wef7YJU//73v10lWRmoCnff+973IhPElmtjQiFXQT7qqKNKXU/DDNTKqslovYr0Bx984CrffsOHD3cBsXvvvTfpnmFt27Z183co8FYdvXOmLM7P6J5hg0+tF3UMhF5U7FNsuhfQVj7i3XuIpvxJeV1FjtFfF+yz6nTtaV83JgBBv/+qswxVU/OniqrufK26kY8ine+/mqa6jxH5E1Az8qdaybwS3CvEiXqSqBCnAp3m+hK9xbE6derUyZ5//vnIzxoi+dlnn5UIhqnnjHqRJaLWEC2xVOnX4udV4mMl6l6cKD32e10w6etPJNjKOOnuM/HSE0wBV+707MpJt+yS+xvvGBwKnsRLT3Tcy5t+xOepAunsU/Lp8dYBgJouHctQAAAASHKYZKIK98MPP2ypoEloTznllMjPAwYMsKlTp9oll1wSSdOwrfnz59sLL7yQkm0EUL00t6AXyFYPNq9bf6KeoQCQKqksQwGAH+UnAEFVoe4Y6vavgpy6+FeldevWuRbTd9991w2pUje73/3ud65X2J133hlZb8SIEW7Y5KRJk9x6GzdudG+XHDlypDVv3rxKtxFAepgwYUKk15p6sGkOjEceeSTVmwUAKSlDAUAyKD8BCKoK9QzThIsffvihVbXWrVvbxRdfbKNGjbJly5a5wmPfvn3t/ffft3bt2kXW01xDc+bMcUGxm2++2c21ofnC9NZJAMGguQb9QXJ5+umnU7Y9AJDKMhQAJIPyE4CgqpVsDy0FmLzJs9WquX37128h1Jxbn3/+uf3jH/9wc3dpotiKip3LXy0TCmppSWYe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Cus0t7q7P7WsosO93fIbtrfinEaWu/MjC7m3zH4tr3EXC2flWL0d0S8F2N/0ZAsVH7TcXSsjaeFQluU17WZZhXts0aLlkXS1yqv1XS8fUMXEo1b5rl27up68GzZsiKQnu08evbxAPe2WL19ueXl5kXT12NPx1/HyB0gUPK5du7YtWrQoap969uxpBQUFtnTp0kiaAiYadq+/p3uSfQruPqXjG5AAlO6Pf/yj3XDDDS4vkCeeeCISUBcFym699VbXg5tgGAAETyjsb6INOF4NXvl49W7yVFn71re+ZTt37oxK11sINfm65pzSyyRatWplDzzwgGWSdH/trtebRBVkbyi35vxSkFIBSz+tc/TRR7teXeoZpv3Seqp8+w0fPtwFxNRCnWzPsLZt27p5xrxjlGzvnCmL91drz7DBp9aNOm70OGKfavo+Kaid7nlUKlF+qnyUn46MrkUF4RWA11ydifzqV79yAXrN71lT1YQyVNCOEfkTUDPyJ3qGAWlCgRHNTaX58TQhuyjjUA+Ie+65xwXJpk+f7nqEIfU09PG5554rka4eMepdokCYt56GTcYGw7Te0KFDE35/nTp13BJLlX4tfl4lPlakBVxBKr/Yn8tKt3Kkh0Iltq+0bSxvur9VP5n0eNtS3nQFT9gn9glAzfH000+73valBcI09+czzzxj77//frVuGwAgPVDaA9KEhgrdf//97s2pehuhAi0qyGmonHqMabiQJmzXEKEf/ehHbujOcccdZz//+c8j80mh+mg4qwJaCnT5KWCp3nyeAQMGuDfd+mnY1vz5861fv37Vtr0AAASBeoiqp9ctt9xS6tuiNeXEiy++aN/85jerdfsAAOmBYBiQRvQmQs19M2nSJBdAUS8xdfHXGw2/+uorFwjTkElvXjENv9P8NqX1MELV0LxdY8aMcUNXNWebCt9TpkyxadOm2ahRoyLrjRgxwubOnevOqYZeaV299UpvyW3evHlK9wEAgEyjOcDUWNijR48Sv9NcnXoGa8L9BQsW2He+852UbCMAIPUIhgFp4rXXXnNvhPzxj39sH330kb300ktuiKSCXXrbkSaTVkBMwRYFYBo0aOC6/6sH2SuvvGJffvllqnchcBT0uvzyy11vPo2Hf+qpp2zWrFluonCPJs+fM2eOC26q95+Cneedd57dfffdKd12AAAykeb0jNcrbPv27W7SfE1f8NZbb7ke9gCA4GLOMCBNKDii135feumlUfOIaT4LBVTuuOMON0H08ccfH/U5BVhat27tepFpcn1UjUTvGlEPLy2l6dSpk7366qtVtGUAAEDU22vz5s12ySWXlPjdzTffbFdccYWbhxUAAHqGAWkk3qTNGzZscBOp9+zZ077xjW/YX/7yl6jfq9C3adMmN2k7AABAkHuFKegVW57S8Ej10lbDIgAAQs8wIE3ceOON9otf/MIaNmzohtHJvHnz7KabbnK9xnJzc+3RRx+173//+26+Kv2roZGaTP/666+3Fi1apHoXAAAAUkKNh2+88YabsiDWunXrXOOhetrHUg97fRYAECwEw4A0oaCW5p3S2yP1hiO1ap5wwgnuzZJ6I6Footd//OMfdvvtt9sNN9zghlEqEHbXXXelevMBAABSRnOAbdmyJe7vTjrpJPeiGwAAPATDgDSiydi1lEa9xvQWSQAAAAAAUH7MGQYAAAAAAIDAoGcYAAAAgOrzyr2W0S4ek+otAACUgWAYUFEU5AAAAAAAqHEYJgkAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAAAAAACAwCAYBgAAAAAAgMAgGAYAAAAAAIDAIBgGAACQgW644QZr2LChNWnSJGoZMWJE1HoTJ0609u3bu3XPOeccW7ZsWcq2GUAwkD8BSLVaqd4AAAAAVL6DBw/aPffcY7/85S8TrvPkk0/apEmT7M0337Rjjz3Wpk6dahdddJEtXrzYjj766GrdXgDBQf4EINXoGQYAABBA+fn5Nnr0aHv22WetXbt2lpWVZVdddZUNGjTIHnzwwVRvHoAAI38CUNUIhgEAAATQ22+/7XpbdOnSJSr9yiuvtJkzZ6ZsuwCA/AlAVWOYJAAAQIZauHCh9e/f3/1bv359u+CCC+yBBx6wZs2a2YoVK6xz584lPtOhQwf77LPP3DCmnJycEr8/cOCAWzy7d+92/xYWFrpF1ItDS3FxsVs8XnpRUZGFw+Ey07Ozsy0UCkW+NyKyzuHvPvRN8dND2Yc+Ey9daeEk0kNmoaxS0otitiVRepZZKBQ//dC2+/dXx0B0bPxq1arljpU/XcdK68ce90TpVX2eEm179qGPFukY+fcpFHanyZ+u/2WHwlYc1pEpO11HMculh6LOdpaFLStkVhQORZ29ROnZFnanqTAcvY1Kj7ftUem+41DV56kmq4r8KS3yKHdvZ2VsHpXsfV6j8yj2ySpjn/z/T0cEwwAAADLQiSeeaB9++KGbl+db3/qWbd682c3PM2DAAHv33Xdt79691rRp0xKfU0VUBeN9+/a5Ca1jjRs3zsaOHVsifcmSJa5CKy1atHCV1jVr1tiWLVsi67Rp08Ytq1atsl27dkXSNUF2y5Ytbfny5ZaXlxdJV68QbYO+O6qgHu5k4awcq7cjejLt/U1PtlDxQcvdtTKSFg5lWV7TbpZVuMfq7lkdSS/Ormv5jbtYrYIdVnvf+kh6UU5DO9Cwg+Xkf2U5eV9G0gvrNLOC+sda7f0brNaB7ZH0g7mt3FJn71rLPrgnkl5Qv60V1mludXd/allF+ZH0/IbtrTinkeXu/MhCrtL6tbzGXSL7tGjR15UW6dmzpxUUFNjSpUsjaaqM9OrVyx3DlSsP72tubq51797dtm7daqtXH97Xxo0bW9euXW3Tpk22YcOGSHpVn6du3bpZ7dq1bdGiRVHnqaeFrMBq2dLibxzeJyu2Xtmf2y7LtZXFh+eDyrUC6569ybaGG9jq8FGH98nyrGv2ZtsUbmIbwoev0xahPdYhtM3WhJvZlnDDw/sU2umWVcUt3d+I7FNoq7UM7bXlxcdYntU+vE9Zm62J5dmS4rZW5BtM0y1ro9W2QltUfFz0PmWtO7xPh/a3Os5To0aNrCaqqvwpHfKoejuLou7nTMujStzPmZhHsU9WGfuk9dNZKOwPLwacWg10wnQxVNeD5a8L9lkmu/a0rx84GemVey2jXTwmo++9muZIjlF15zMZfd8jkDIpj1JvCRW2X3vtNTcM6YMPPrC///3vUeuoIKvJqbVusj3D2rZta9u2bYscn6pu+Z6yOD9je11oGwefWi/qGGRcD4VZ4zK7Z1i/0dV2nhQ0In9KrzxqyuL9Gd0zbPCpdaNSMzKPYp+sMvbJC2qna/5EzzAAAICAqFOnjpuHR626GoL03HPPlVhHrdJq4U1U0dR3aImlArUWP6+AHMsrlCebHvu9rqL29Sfirh833X0mXnqCoWblTs+unHTLLrm/8Y7BoYpJvPREx7286Ud8nhKlHzp9tWIr+IdOU7x0BayyypUejjs5sgJoVo70WonSrZT0mP2t6vOUKSojf0qLPCrq3s68PCrp+7wm51GlpLNPlnR6uudXBMMAAAAC4osvvnBDIU4++WRr3ry5q1hq/p2OHTtG1pk+fboNHDgwpdsJIHjInwBUp/QO1QEAAKBCNP/OQw895IYVadjC4sWL3Xw8w4YNc70vNHfOmDFjbMiQIbZx40Y3RGLKlCk2bdo0GzVqVKo3H0AGI38CkGr0DAMAAMhAqkQ+/PDDbnLq7du3uwrmz372M7vpppsi66hSqaEXffr0cRPlaiLdWbNmucl6AaCqkD8BSDWCYQAAABlIQ42eeeaZMtcbOXKkWwCgupA/AUg1hkkCAAAAAAAgMAiGAQAAAAAAIDAIhgEAAAAAACAw0j4YdsMNN1jDhg2tSZMmUcuIESOi1ps4caK1b9/erXvOOefYsmXLUrbNAAAAAAAASE9pP4H+wYMH7Z577nGv303kySeftEmTJtmbb77p3kQydepUu+iii9wreo8++uhq3V4AAAAAAACkr7TvGVaW/Px8Gz16tD377LPWrl07y8rKsquuusoGDRpkDz74YKo3DwAAAAAAAGmkxgfD3n77bdcbrEuXLlHpV155pc2cOTNl2wUgGBjKDQAAAAA1S9oPk5SFCxda//793b/169e3Cy64wB544AFr1qyZrVixwjp37lziMx06dLDPPvvMDbPMycmJ+70HDhxwi2f37t3u38LCQreIepppKS4udovHSy8qKrJwOFxmenZ2toVCocj3RkTWOfzdh74pfnoo+9Bn4qUrLZxEesgslFVKelHMtiRKzzILheKnH9p2//7qGIiOjV+tWrXcsfKn61hp/djjnii9qs9T3G0Phyz70PEr0jHy71Mo7E6TP13/yw6FrTisI1N2uo5ilksPRZ3tLAtbVsisKByKOnuJ0rWNOk2F4ehtTLTtkfSYY1CV58n//5qGodwAAAAAULOkfTDsxBNPtA8//NBVNr/1rW/Z5s2bXaVzwIAB9u6779revXutadOmJT6nQJkq7vv27XO9NOIZN26cjR07tkT6kiVLXNBNWrRo4QJra9assS1btkTWadOmjVtWrVplu3btiqSr50fLli1t+fLllpeXF0lXzzVth747KpgQ7mThrByrtyO6l8j+pidbqPig5e5aGUkLh7Isr2k3yyrcY3X3rI6kF2fXtfzGXaxWwQ6rvW99JL0op6EdaNjBcvK/spy8LyPphXWaWUH9Y632/g1W68D2SPrB3FZuqbN3rWUf3BNJL6jf1grrNLe6uz+1rKL8SHp+w/ZWnNPIcnd+ZCEXWPtaXuMukX1atOjrIJL07NnTCgoKbOnSpZE0BUx69erljuHKlYf3NTc317p3725bt2611asP72vjxo2ta9eutmnTJtuwYUMkvarPU7du3ax27dq2aNGiwyep+DjrmbXOCqyWLS3+xuF9smLrlf257bJcW1l8ONCRawXWPXuTbQ03sNXhow7vk+VZ1+zNtincxDaED1+rLUJ7rENom60JN7Mt4YaH9ym00y2rilu6vxHZp9BWaxnaa8uLj7E8q314n7I2WxPLsyXFba3I1xm0W9ZGq22Ftqj4uMP7pPPk7ZNvX6v6PGn9TOUN5X7vvffcUG7RUO7333/fDeX+/e9/n+pNBAAAAIBACYX93WJqCPXmUoDjtddec8MkP/jgA/v73/8etY4q2upxoXXL0zOsbdu2tm3bNmvUqFG19Diasjg/o3uGDT61XtQxyKieYbP+J7N7hvW7vdrOkxfUVrDNu/dqiqFDh9pJJ52UsGfYrFmzXDDsP//5T1S6gmP6rAK1yVD+pKBhRY7RXxfss+p07WlfNyYAmeJI7r8gSMXxqe58rbplfD76yr2W0S4eU21/ivwp/Y4R+RNQM/KntO8ZFk+dOnXcUCP1OtEQyeeee67EOqpgqgdKokCY9z1aYqnSr8XPq8TH8oIkyabHfq+LUnz9iQRbGSfdfSZeeoIp4Mqdnl056ZZdcn/jHYNDwZN46YmOe3nTj/g8xUsPHQ451YoNQh46TfHSFbDKKld6OO7kfgqgWTnSayVKtwTp1Xie4q1Tk1TVUG4AAAAAQOWrkcGwL774wg3VOvnkk6158+Yu8KVKZceOHSPrTJ8+3QYOHJjS7QSQ+apqKHelzmkY6b1Z8V6e5em56u9ZWSN6eWZiz1X2qVL3CQAAAJkl7YNhqlS2bt3arrnmGhf40lxOP/nJT2zYsGGud5iMGTPGhgwZ4ialbtWqlRsyOW3atOj5nQCgCvzqV7+K+llDuJ999ln3r4ZGNmjQwHbu3Fnic0pTpdybn7Aq5zSst7PoiOf/K8+chosWLa9Z8/9l4pyG7FOl7lM6du0HAABABs8ZtmzZMnv44Yfd/GDbt293AbCf/exndtNNN7mKpOcPf/iD/elPf3KFXhWKH330UTvhhBPK9beY86LyZfSYcua7CMx48oo49dRT7Te/+Y37/9133+3eHOmnXmOaM+zTTz+t8jkNpyzeX609wwafWvdwEj2O2KcM2Cf18My0PKoyUX6qfBldfhLKUJUmE8tQlY05wypXxudPCEz+lPY9wzQU8plnnilzvZEjR7oFADJhKHelzmkYO69fBeb/Szq9Js7/l4lzGpaRzj6VPx0AAACZg9IeABzhUO6HHnrIDatSbxL1ANN8Yd5Qbg1p9IZyb9y40fVcmTJlihvKPWrUqFRvPgAAAAAETtr3DAOAdKYgl4Zya/L82KHcHgW91COmT58+kaHcs2bNcnMoAQAAAACqF8EwADgCDOUGAAAAgJqFYZIAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAAAIDIJhAAAAAAAACAyCYQAAAAAAAAgMgmEAAAAAAADVIBwO27Rp06xfv37WqlUra9GihQ0cONA++eSTVG9aoBAMAwAEBoUPAAAApNKuXbvskUcesVGjRtnatWvt888/tzPOOMP69u1re/bsSfXmBQbBMABAYASt8NGyZUvbunWrZaJM3jcAAJC5GjdubHPnzrXzzz/f6tata7m5uTZ69GiXvnDhwlRvXmAQDAMABEZQCh/79u2zhx9+2LZs2WKZJpP3DQAAZL5QKOQWv4MHD9r27dutUaNGKduuoKmV6g0AAKC6xBY8MrHw8fjjj9vIkSOtuLjYMk0m7xsAAAjuNB4333yzde3a1Xr27JnqzQkMeoYBAAIrEwsfw4YNs/3791t+fr5lmkzeNwAAEDw7duxw89euWLHCpk+fnurNCRSCYQCAQKLwAQAAgFRZsGCB9erVy0499VSbM2eONWnSJNWbFCgEwwAAgUPhAwAAAKny8ssv2/e//3179tln7Z577rGsLEIz1Y05wwAAgSt8DB8+3J5//nnr06dPqjcHAAAAAbJt2zY39cNrr71mJ5xwQqo3J7AIhgEAAoPCBwAAAFLpxRdftEGDBlEWTTH64gEAAoPCBwAAAFLps88+syeeeMIaNGhQYrnttttSvXmBQTAMABAYFD4AAACQSg8++KB7M/bevXtLLA888ECqNy8wMioYtn79evdmsMaNG1vr1q1t7NixVlxcnOrNAgDypzRB4QMoifwJQLoifwJQVTImGLZv3z7r27ev9e/f380Js3jxYps3b57LMAEglcifkCrhcNiOOuooy0SZvG/VifwJQLoifwJQlTJmAv0JEyZYjx497MYbb3Q/H3PMMTZ58mTr2LGjjRgxwpo3b57qTQQQUORPANIV+ROAdEX+hJR45V7LaBePSfUWpI2MCYbNmDHDRo8eHZXWsmVL6927t82ePdsGDx6csm0DEGzkTxlWaKEQgQxC/gQgXZE/AahKGRMMW7FihXXu3LlEeocOHdzv4jlw4IBbPLt27XL/bt++3QoLC93/s7Ky3KKx6f7x6V56UVGRG6pRVnp2draFQqHI93ry9uYf+l9xghGssenZGhySIF1p4STSQ4e+P1F6Ucx3JErPOvS7ooTbvn37gahjIDo2frVq1XLHyp+uY6X1Y497ovSqPk9xt33fAcs+dPyK3HHw7VMobPpaf7r+lx0KW3FYR6bsdB3FLJceijrbWRa2rJBZUTgUdfYSpWsbQyGzwnD0Niba9kj69u3Vdp40X5P4z0UmSXX+lLd3/xHfy+XJn/z3fbXcy/vzK++6T+Ze3rGjWvOnJ7580aWHD52mUMxpcun6VXGS6YceI1HpoUPrh81+2vKKKt+nqDx3yl+tMM6VZHGuyETpKsyEY9Jd3nroKo3a1at+WO59yuQ8KtX5U1nplJ8ysPyk9H35mVt+UrqvDFXV54n8Kf3yqK/LXVkZm0f58yfvGGRUHkUdz4JSx8uYYJgOdNOmTUukN2vWzPbs2RP3M+PGjYs75vz444+vkm0Mop+megNwBO6v9r+oe1UTpGaaoOVPmX/f/9Yy2Z2ZfgZvGlHhj2ZiHhW0/KmmyPC7MACq/zlB/nQYeVTVIn+q6ajjZVwwrEGDBrZz5043ltxPacow47n99tvt1ltvjfysKKZaDDT+XFHPTLN7925r27ateytLo0aNUr05KIdMP3dqLVAmqbcEZaKamD9l+jXH/tVs1b1/mZxH1cT8qbpl+v2U6TL9/JE/BTuPyvTrO9Nl+vkLp3n+lDHBMHWh/eyzz6xr165R6atWrbKhQ4fG/UydOnXc4tekSRPLdLrRMvFmC4JMPnfp2FpQWWpy/pTJ15ywfzVbde5fpuZRNTl/qm6Zfj9lukw+f+RP0YKYR2Xy9R0EmXz+Gqdx/uQNWq7xBgwYYFOnTo1K27p1q82fP9/69euXsu0CAPInAOmK/AlAuiJ/AlCVMiYYptfrzp071yZNmuS6wm7cuNGuuuoqGzlyJK/dBZBS5E8A0hX5E4B0Rf4EoCplTDBMkyvOmTPHtR6oG2yvXr3svPPOs7vvvjvVm5Y21F34nnvuKdFtGOmPc1ez1cT8KdOvOfavZsv0/atONTF/qm5cbzUb56/mIn8qG9d3zcb5S61QOF3fcwkAAAAAAABUsozpGQYAAAAAAACUhWAYAAAAAAAAAoNgGAAAAAAA1UQvBCiPgwcP2t69ey3VmGEJmYRgWADoFcTDhw+31q1bW8OGDe2UU06xp556KtWbhTJs2bLFWrVqZS+//HKJ3918883Wp08fKyoqSsm2AQCQ6Sg/1UyUn5Au/v3vf9uAAQNKpM+ePdvOPPPMEulvvvmmXXLJJXG/a9GiRXbhhRemLBgn7777rp122mmVtg1IDvlV1alVhd+NNLBp0yY766yz7LLLLrP//Oc/1qJFC1u8eLH99Kc/tfnz59vTTz+d6k1EAjpXOj8/+clPXMGtWbNmLv1///d/7dlnn7UPP/zQsrOzU72ZqIG2bdvGK8mRttauXWvt2rVL9WYg4Cg/1VyUn5AuPv74YzvmmGNKpOv6y83NLZFet25dmzt3rgu85+TkWO3ata2wsND1CtuzZ4+1bds2qb/7m9/8xh5//HGrX7++1atXz72pMCsrywVV9H3qYbZ//35bv3595F4YM2aMvfjii1arVi0XKPMWNQa8/fbbbh1tjxaUrUOHDjZv3ry45z+R8ePH27Jly+zPf/5zVPqPf/xj9/zRuQmFQu6c+c+Ryk1PPvmkXXXVVVWwJxlOb5NE5urXr1/41ltvLZG+c+fOcLt27cKTJ09OyXYheTfeeGN48ODB7v/79u0Ld+jQIfyXv/wl1ZuFGmrVqlXh7t27h5cvXx7OVIWFheFMU1xc7P59+umnwy+//LL7/8GDB8OZZtGiReGjjz46vHr16lRvCgKO8lPNR/kJqXbGGWeETzzxxBLlk9dffz38ne98p8T677//frh///7hoqKiEr+bP39++Pzzzy/X358wYUL49ttvj/y8YcMGdx94ZQq/eH9z3rx54QsvvDDy84cffhg+++yzy7UNmWrNmjXhoUOHhs8888zwNddcE162bFnU748//vjwli1botI2b94cvuGGG8Knnnpq+LLLLgsvXrw46vePPvpo+Lrrriv3tmgb3nnnnQruSbAxTDLDWyMUkf71r39d4neNGzd2LQAPPfRQSrYNyfvDH/7gukb/85//tNGjR9u3vvUtGzJkSKo3CzVE7NwOLVu2tO9+97v2xz/+0TLN0qVLbdiwYfb+++9bplFLoKhV94c//KH7v1oIM82pp55qp59+uv3pT39K9aYgwCg/ZQbKT0glDYX84osv3PP7lVdecWkaAqnn3PXXXx937i31ANP66sUVS2nq1VUenTt3toULF0Z+/uijj6xLly6RMkXs98d65513XO9Kj3okZWLZo7x27txp/fr1syuuuMJee+01u/TSS93P6lHsUc8+P/Xguuiii1w+NGfOHJcX6XpQ7zyPet0lM3xV146uFQ0JV4+xzz//3Nq3b1/JexkMXM0ZTBnY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0ackEjfVxIkT4+cMGTIkCmGAUES5JGWUHTt2DKXSAAAHG2SFsPQdbLPNNtHVRkg+ZaF0LOX7QBRs3bp16NWrVzj//PPjsgphIiIiIiIrh2KYiIiUFMkNRhD+T3/60+h4otQRh9f8+fPDoEGDoluKTK0siF5/+9vf4vv/+Mc/xvdtuummudcRxg466KCw1VZbhT322CMUGwSvnXfeOXYgHT58eKUulykHbffddw/t2rWLZaE4we68885w3nnnhVtuuSUuh5A2evTomDNGIwAREREREakdp5FFRKSkwAl10kknxdD4nj17xowwSgSB0Hiys5YtWxb+/ve/R5Ho6quvDptvvnnssgi4vzbccMMoJlFeSc7WddddF51VQ4cODbvssktRw/9TOSOCF10s27RpE0tAjzvuuPjztDwNARDMRo0aFSZPnhy6desWyyHzM9IQ0hDU7r///pLsiikiIiIiUmroDBMRkZICIet3v/tdGDt2bHRxIYyNHDkyvta2bdvw2WefxQwtAuQ7dOgQhTCEL0BI2mCDDWKWFh0nr7nmmnDDDTfEjouIRg0thEESwt56661K5Yz9+/ePQhjusLXWWit2kIS0LW+//XbYc8894/Mnn3wyln9mGTx4cCwdRTQbM2ZMLP8UEREREZHaMUBfRERKFpxRlDzi9jrggAPCnDlzQu/evaNLKmVlJb766qsoKmX55JNPKpVKFgMus7i2cLC988474bnnnouh94h+N910U9hrr73CzJkzY0kkmWBpfVl3nF+44fj5YYcdFv7xj3+E2bNnh8svvzxstNFGUTTcbbfdirp9IiIiIiKNDcskRUSkJMERheuJrLDjjz8+ZoXtsMMOMUeM51nIF0MkQ2jaaaedcqWGxRbCgPXYf//9o9iFsMU64Wr79a9/HV9HCEPcIix/8eLFsVskJZRp3REEKQFlm7fYYotYNnrJJZfkgvdFRERERKRuWCYpIiIlCUIYXRR//vOfx/yw8ePHhwcffDA0b948DBs2LC7z8ssvR8fYQw89FB544IEohEE2o6sUQOg666yzYidMMsAQwnCyXXHFFaF9+/Zh3333jflmrH9qIIAwBun5mWeeGUU/3GEKYSIiIiIiq45lkiIiUrLQKfGjjz7KuahgxIgRMUNs6dKlYeHCheGiiy4KJ598cs5FlcSjUoPQ/+7du4cVK1bErpY33nhjLP/s1KlT6NevX6XumLzWp0+fMHHixOiGExERERGR1YdlkiIiUrIcfPDBVX6GG2zKlCmhS5cuudD5UhfCYP311w9nnHFG6Ny5cyyNxM2GUwwh7Omnnw4dO3YM48aNi2H/dM98+OGHFcJEREREROoBnWEiIlKypOwvoAzyD3/4Q2jdunX8t0WLFo1CBMtCuecHH3yQK+cEQvQpB12wYEEM2O/Ro0cU+hrbtomIiIiINBZ0homISMmCEDZ58uRwyimnhGbNmsXOkmRsZYWixiQWrb322pWEMJgxY0YYM2ZMzBR79tlncz9XCBMRERERqR8cZYuISEnz5ptvhhNPPDFMmDAhCmG4xXg0dqHo7rvvDtttt13MREPwu/baa3MiGDT27RMRERERKVUskxQRkUZDU3BLTZo0KRx77LFhvfXWC7feemsuF60pbJuIiIiISGNAMUxERKQBGTRoUJg7d2644YYb4vN0GU7ZaCIiIiIiUr8ohomIiBQJ3WAiIiIiIg2PYpiIiIiIiIiIiJQNTkeLiIiIiIiIiEjZoBgmIiIiIiIiIiJlg2KYiIiIiIiIiIiUDYphIiIiIiIiIiJSNiiGiYiIiIiIiIhI2aAYJiIiIiIiIiIiZcN3i70CIiIixeC///1v/Pd//qfqvNB//vOfsHTp0tC8efM6f+6GG24YFi1aFL773eovse+9917o1KlTWGuttcJ3vvOd8O9//ztUVFTEdbr33ntDmzZtwscffxz22GOPMH/+/ErvTcvxvnx47dNPPw2bbLJJnddbRERERKRcUAwTEZGy5Pnnnw/nnntumDFjRpXX3n333ShELVu2rJJY1r179/i+ddZZJ/4c0eyLL76I4tWwYcPiMt/73vdqFMKgZcuW4Y033ghrrLFGePzxx8Odd94ZHnnkkbBixYrce/l8xLJCQtquu+4af2++kIeotummm4aFCxeGzTfffJW/GxERERGRpoximIiIlCWIToXEJlhzzTWjqJUvNvXt27fKsi+++GIYNGhQ7jkC18qQlpswYUJ4++234//5nbi7gH95Xmi9//d//7ego43l+VzWX0RERERECqMYJiIiZQnC0bRp08L3v//9KCxlH6mEsjreeeed6A7bcsstw9dff11JVEti1spASePQoUNjaeWIESNC586do1tt0qRJ1ZZCst6UcBZabx51+f0iIiIiIuWIYpiIiJQliE2tWrUKs2bNqvLanDlzwm677Vbte++6667wgx/8IHTp0iUsWbIkOrXqCoJWx44dQ7du3cKRRx4ZDjnkkJhRdvvtt8fX586dGw4//PCC640gxuuFwBmmICYiIiIiUj12kxQRkbKEfC0yv/KFoxRQz2vVgRiVBDCW3WGHHXKvkTN2xBFHhKOOOiqG4Bdi5MiRYd999w0dOnQIl112Wcwce/TRR8Mll1wS+vfvn1uPuqx3ei1lmYmIiIiISGF0homISFlCCeLy5cvDtttuG4UtHF4ISWuvvXYUmiiBzILolc3p+uqrr8LixYvDj3/841gqSRB/ixYtYskkpY8IUhtvvHG17q2//vWv4Uc/+lHuZ3vttVeYMmVKXCeoyd1FOH5ab4L0Cd5ff/314zputdVWq+HbERERERFpuqxRYS2FiIhIOPXUU8Oee+4ZyxYLMXz48HDxxRfHAHucYYhmPNZdd90oRPHA5bX//vtHYe3bgsj17LPPhk6dOtW43DXXXBNLLvv16/etf6eIiIiISDmgM0xEROT/d2msqQvjcccdFx+4wD755JOw9dZbV1kGh1ZdmDp1aujVq1fMKAPcZLjPvvnmm7DzzjuHnj17fuv1FhERERGRyiiGiYhIWZEywfI7NSJA8eB1HghTPMd1RVliWn7evHnhpJNOChMmTKjy2bV1oczn6KOPDg8++GDYe++9q7z22GOPRVcY5ZfZTDDEr5VZb7LLNtpoI4UyEREREZE8FMNERKSsmDlzZnRdUepIaSPiUsoDGz16dOjdu3d8nkL0EZjefvvtXBYX78sX0hJkeI0ZM2al14XfOX/+/Cp5ZMDvoAwzm1HGc9aX9WY9eB/5Y7z3gQceqLLeTz/9dNhvv/1W+bsSEREREWmKmBkmIiJlBZc9nFOr6ph67733Qtu2bWOAPSIUDwSprIg1ZMiQGIhfG7NmzYri2+TJk3PiVhLaWrduHa6//vrQsmXLSoIYAf0iIiIiIrLqKIaJiIh8CxCwuJTmi2IiIiIiIlKaKIaJiIiIiIiIiEjZUDmgREREREREREREpAmjGCYiIiIiIiIiImWDYpiIiIiIiIiIiJQNimEiIiIiIiIiIlI2KIaJiIiIiIiIiEjZoBgmIiIiIiIiIiJlg2KYiIiIiIiIiIiUDYphIiIiIiIiIiJSNiiGiYiIiIiIiIhI2aAYJiIiIiIiIiIioVz4f3ItDKqlrd3jAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "store_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"๋ณด๊ด€ ์ •๋ณด\"]]\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "##### ์ „์ฒด\n", + "plt.subplot(1, 4, 1)\n", + "bars = store_df[store_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\"][\"๋ณด๊ด€ ์ •๋ณด\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.title(\"์ „์ฒด ์ƒํ’ˆ๋ณ„ ๋ณด๊ด€ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = store_df[(store_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (store_df[\"๋ณด๊ด€ ์ •๋ณด\"] != \"์—†์Œ\")][\"๋ณด๊ด€ ์ •๋ณด\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=30, ha=\"right\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.title(\"์ด๋ฏธ์ง€๋ณ„ ๋ณด๊ด€ ์ •๋ณด ํ‘œ๊ธฐ ์œ ํ˜•\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "##### ์ˆœ์„œ ์œ ์ง€\n", + "plt.subplot(1, 4, 3)\n", + "bars = store_df[(store_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (store_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"๋ณด๊ด€ ์ •๋ณด\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ์ƒํ’ˆ๋ณ„ ๋ณด๊ด€ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = store_df[(store_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (store_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & (store_df[\"๋ณด๊ด€ ์ •๋ณด\"] != \"์—†์Œ\")][\"๋ณด๊ด€ ์ •๋ณด\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ์ด๋ฏธ์ง€๋ณ„ ๋ณด๊ด€ ์ •๋ณด ์œ ํ˜•\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์„ฑ๋ถ„ ์ •๋ณด (์ „์ฒด ์ƒํ’ˆ)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKEAAAJOCAYAAABvBRRKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA4JpJREFUeJzs3Ql8VOXV+PEzkx0IS9iRfROQRRQEpCrwoi+rVLEvFCtgLaWAgkqlKItFfeVVURRREbVoFaQIRfRPAREERSkQCmWRRQvIKrIFQsie+X/Og3cyM5kJk5CZzEx+38/nijm5mbl3hjzce+Y857E5HA6HAAAAAAAAAAFkD+SDAwAAAAAAAIokFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAIuOvBPERny8vLk+PHjkpiYKDabrbQPBwh7DodDUlNTpU6dOmK3kw+/GoxPQMlifCoZjE1AyWN8KhmMT0DpjU8kofykg1S9evVK+zCAiHPkyBGpW7duaR9GWGN8AgKD8enqMDYBgcP4dHUYn4DSG59IQvlJs+TWC1qxYsXSPhwg7F24cMH842/9bqH4GJ+AksX4VDIYm4CSx/hUMhifgNIbn0hC+ckq09RBioEKKDmUQF89xicgMBifrg5jExA4jE9Xh/EJKL3xiYnEAAAAAAAACDiSUAAAAAAAAAg4klAAAAAAAAAIOJJQAAAAAAAACDiSUEHw9ddfy6BBg6RmzZqm8V2XLl1k3bp1Bfb7z3/+IwMHDpSqVauaffv37y979uxxfv/SpUvy8ssvS+fOnSUpKckse/jggw/K+fPng3xGAIBIVKNGDTl9+rRb7OjRo/LYY49Jq1atzL9h1157rfm3yNWIESPMSiiVK1d228aOHevzuV5//XXzbxgQ6tdpP/30k0yePFlatGghFSpUkIYNG8rTTz8teXl5bo/DdRqAYI9Pn3zySYF/e3XTsWrkyJHO/RifEEpIQgXBuHHjpHfv3nLgwAE5c+aMuZjXZNP+/fud++j/33rrrdKjRw85fvy4HD58WO6//345duyYc5/PP/9cduzYIW+99ZacOnVKtm7dai6Mhg0bVkpnBgCIBGlpaebiVP9t8TRnzhypVKmSfPbZZ+ZidcmSJfL222+7JaKys7PlySeflJSUFLdt1qxZXp9v37598sYbbwT0nICSuk575ZVXJDU1Vf7xj3/IxYsXZfXq1bJ8+XJ59tln3R6H6zQAwR6f7rzzzgL/9urWoUMH6dmzp/NxGJ8QSmwOh8NR2gcRDi5cuGAuwvUCvKjLeOoFi2ajXf3hD3+Q6667Th566CHz9W233SaDBw+WUaNG+Xyc3NxciYqKcovpJ9a1a9c2NxCxsbFFOi4gXH+n4I7XEldDk0Hjx483VR2ZmZnm4rRatWqF/tuzePFik2D68ssvzdfDhw+X1q1byx//+McrPl+9evXMc+Tk5Jh/C2fPni2hht+psvU6Xuk6zdv3//nPf8qYMWPMjZyF6zQEQ7j8XoW6cHkd/bmP9LRt2za56667zCwba0xifEIo/V5RCRUEngOHSk9Pl/Lly5v///bbb820u9/+9reFPo7nwKFOnjwp5cqVk+jo6BI8YgBAWaEffmiZfkZGRpH+7SnuRfuRI0fMc+n0JiAcrtOu9H0L12kASpq/44+rmTNnmgSV65jE+IRQQhIqyDTjrAODfnKm83vVN998Y0omv//+e1NeWatWLWnatKlMnTpVsrKyfD6WZhg1caWfYNvtvJUAgMDbvXu3TJs2rUDV05YtW6RPnz5SvXp10zNH+0SdPXu21I4TKKnrNFeaQP3iiy9Mv7Mnnnii0MfiOg1AMMcndeLECTN1+He/+12hj8X4hNLE37gg0Uau+qmxNpXTT3+1jDI+Pt58T+fjah+oX//612Ze7qFDh2TlypWm/8bEiRN93gRoY7quXbvKlClTgnw2AICy6O9//7vcfvvtpkdOt27dnHGdFqAXsdoXSv8927Bhg+mh069fP2HWP8L9Ok1p4lWb/eo0A+3f2bJlS2nTpo3Px+M6DUCwxifPRT/uvfdeM1b5wviE0kYSKki0CavOkdTKpk2bNpnGrtpLQOkcXG00pw3jtLmcDipaCTVv3jx58803C6y+8u6770qvXr3kf//3f+Wll14Sm81WSmcFACgL9N+uhx9+WP785z+bpsz6oYkrbZT64YcfSqdOnSQmJsasuvPee+/Jd999J9u3by+14wZK4jpNWY33rb5pbdu2NX/fvVX7cZ0GIJjjk2ulpjYeL2xlWsYnhAKSUEGm83G1eetrr70mCxcudGa3ExISzNLYrjSuFztaKWXRyihNTG3cuNE0nAMAIJD036E77rjDNC7dvHmzqXryR1xcnNSvX99URgHhfJ3mSRv3azVCnTp1nM35LVynASit8en99983FU5NmjTx+vOMTwgVdCErJceOHXOWSWpZt87x1el3eqHvurJBYmKi6a+h1qxZY5YE1hVZCmtGBwBASXnmmWekUaNG5tPVotC+FHv37i10yhIQDtdp3ujqjvohoes+XKcBKM3x6eWXXzYr3nrD+IRQQiVUEPTv318+/vhjUyKpFy3a0FIbtmrjcaUDgZZD3nfffbJixQrJzs42c3W1WZw2vbRWM9AbgKeeeoqBAwAQNH/5y1/khRdeKHQfbVKu/47pNCWdQq5NU7UflK68p9VQQDhfp7344oumJ5QmVq0VHrXnijbgv+2225yPw3UagGCPT5ZVq1aZli633nqr18dhfEIooRIqCMaNGyezZs0yqxToxXmLFi1M0zhdRcgyfPhwswTnn/70J9NDQ0u8H3nkEXnwwQed++jqeb/5zW+8zt3Vkky94AcAoKRcvHjR3HjrzXZhn8bqohr6CewNN9xgeuRo4kn//Ro9enTQjxkoqitdp2kPNE3E/uIXvzDVT7Vr15bBgweb3p2uq0pxnQagNO4jla6ap/eOvjA+IZTYHCxb4xdtBqcX2rqcpa5OAODq8DtVcngtgZLF71TJ4HUESh6/VyWD1xEovd8rpuMBAAAAAAAg4EhCAQAAAAAAIODoCRVgf92cFrTnGnoTjeYAAD9b/rREnL5TSvsIEMKCec0VTFzfAeEvEscnxiYUF5VQAAAAAAAACDiSUAAAAAAAAAg4klAAAAAAAAAIOJJQAAAAAAAACDiSUAAAAAAAAAg4klAAAAAAAAAIOJJQAAAAAAAACDiSUAAAAAAAACi7Saivv/5aBg0aJDVr1pSKFStKly5dZN26dc7vf/nll1KuXDmpXLmy21atWrUCj7Vr1y7p1q2bJCYmSqNGjeT1118P8tkAAAAAAACUbSGbhBo3bpz07t1bDhw4IGfOnJHHHntMBg4cKPv37zffz8vLk8aNG0tKSorbdvr0abfHOXbsmPTp08c83oULF2T16tUyd+5cmTdvXimdGQAAAAAAQNkTLSFKq54qVKjg/Pruu++Wzz77TFatWiXNmzf3+3GeeeYZGTJkiNx1113m66ZNm5oElCamhg4dKlFRUQE5fgAAAAAAAIRBJZRrAsqSnp4u5cuXL9LjLF26VAYPHuwWa9++vZmat2nTpqs+TgCRq0aNGgWqK48ePWoqM1u1amWmCl977bXy8ssvF/jZI0eOyIABA6RSpUpSp04dmTZtmqng9DRnzhxT1alj0q233io7d+4M6DkBAAAAQGkJ2SSUK70JnDlzpmzdutX0ibJcvHjRTLPTG7jq1avLbbfdJhs2bHB+/9y5c3Ly5EmvlVNNmjSRPXv2BO0cAISPtLQ0k1g6deqU16SRJpa0MvP8+fOyZMkSefvtt90SUfrzPXv2NBWXOp1Yxy4dmzQR5cqaGrx27VrzWKNHjzbTkHXcAgAAAIBIE7LT8ZRWGJw4ccLc0MXHx8tzzz1n/lRVqlQxySWtatIbu5iYGFm8eLH06tVLNm7cKG3atDFJqtjYWNPA3FNSUpKkpqb6fO7MzEyzWbSflMrJyTGbstvtZtPqBtcKByuem5sr4sh1eVSbiM3uETM/IWKzeY8beX7GRRwOx+XntZ7RZjNTDj2P0Vfcn3PS57hSXB9bn8N6rVzjyvUYC4tHR0dzThF8TqHojTfekPHjx/s8Ph1vXKfxtm7dWv785z/LrFmz5OGHHzax2bNnm7Fp5MiR5uvatWvL/PnzzXTgsWPHStWqVSUjI0MmTpwo33zzjTRs2NDsp1WbOn7NmDFDXnjhhaCcLwAAAAAES0gnofbt22f+1BtbrVp66KGHzEp3WonQrl07U4ngatiwYabiQKsSXnnlFTOlLysry0zjS0hIcNtXm5jr9Bdfpk+fXqBqQW3bts05JVCrr7Si6uDBg24VE3Xr1jWbNlEvd+6sM55Vvp7kxFWV+AvfiT03wxnPSGwseTEVJSFlt9gc+Te+6ZVaiMMeI+XOuU/PuVSljdjysiXh/F5nzKHJLeliqin27s2P63nra6XVZNrk3aKVHC1btpTjx4+b6UUWf85Jn8OiVWg6ZUnfF32dLS1atDCrFerr5ZqYaNu2rUkMJicnu51Thw4dzHu1Y8cOZ0xv9Dt27Mg5Reg5aYI5FI0aNcpsVsLMk7c+clq5pFPzXKcBa4LJlb7+nTt3Nn3ttE+d9r2rX7++eQ9cabXn8OHDSUIBAAAAiDg2h2tZRIj79ttv5eabbzYJJF9effVV+fLLL+Wjjz5y3qzrVBetjHLVrFkzeffdd6Vr165+V0LVq1fPTK2xbjb9qUaZn5wWtEqooZ0qUmHDOYXNOenvsVY0avLKNYETSvRYNclXrVo1n/vs3r1bunfvLosWLZJu3bo5E21a0aR9o1xpcksf6+mnnzZTjHUf/TnPhJZWTun4oxWe/tDxSZ8zlF9LlILlT0vE6TslKE/D71R4vo5/3ex6zRU5ht5UtH6oiGyMTyWD8enqMTahuL9XIV0J5enYsWPmpArz+eefy0033eT8ul+/fuYmzzUJpVUcOhWvU6dOPh8nLi7ObJ70Zls3V9YNvidzw27zsvqet1hhcfE/rjfNnsdX2DEWNe5rNUFfcW/HUtQ45xS55xTu/v73v8uDDz5oKi+tBJTSqcCaYCtsGnBh+2hCT6cha5VaIKcLh3qiMhKTr0E9J4dNouTyPrn6IYjrOfmIR9scog/rGtf/i7I5JM+hH31cOa6/2XYTt7l9VGIXh9htIrkO28/PXnhcj1E/n8lxuBxjTk6Zni4MAAAQ7kI2CdW/f3954IEHTI8nvYD86quvZMSIETJ16lTzfa12evPNN80qVTrlRyuUnn32WVOV8N577zkfZ9KkSXLLLbeYaTB9+/Y1U/yGDh1q+kv5usEGgMLolMQJEyaYKsvVq1fLdddd5/Z9nQqslV5a0eRKY5pkct3Hk8b0RriwlUBLarpwqE/ZjMRpqEE9p7wG0tZ+TGIlR5LzGrifk/0HyZJo2ZF3Tf45SZ50jDos5yVB9ubVzD8nyZJ2UcfltKOCHHDkVwVWknRpGXVSjjsqy1FHfsK0ui1VmtjOyEFHkpxy5E97r2tLMdv+vBrmOZznZDstNWwXZVdebUmX2Pxzsp+UypIu2/LqSa5VAZycXKanCwMAAIS7kJ2OpxVN2uhXm/bqJ5J6gT158mSz2pRVRaDNf7XKSS/S9YJSE1f/93//Zy7QXW3ZskUeeeQR+fe//22mwjzxxBMmoRWMks1gll5SEolwEg7l5N6m42kF0n//93+bKb06/ddaLMGV3vRqwlzHJFe333676fd07733yvLly80+2sfO1ddff232+e6773weV0lNF6ZqKMLPaeX/RV4lVK+JTBcOI0x3KRlc3yHcrp/CAePT1WNsQsRNx9PlzXXzRasItPGvZ/Nfb/SGUJdHB4Cr9cwzz0ijRo3krbfe8rmPNQ3YNQmlFRebNm2ShQsXmq91+p4m0L///nuzap5lyZIlMmDAgEKPocSmC4fBlM1InIYatHOy5ad0ot3SO1JoXBM/3uKaKLIXKe5wdjB0O3aX4/Inromx/C/yz4/pwgAQPvRDNi0w0IVZtJJXq8i1sttqZ6CzXHQGjFa6utKxW6+hXGk1sLZD0A/y9INCnRkzevTooJ4PgOLjKgsAiuAvf/nLFVeuGzt2rKxfv17mzZtnqiy0n93gwYNl/PjxUrVqVbOPTpubMmWKWdVTv69VGgsWLJDFixebqX4AAACRYty4cdK7d28zBVortzVxNHDgQPOBnNLrJZ1yrpWorptnAkqvmXRmjD6eVl1oW4S5c+eaay4A4SFkK6EAINToNGDtFdOwYcNCF0/QaTxr1qwxySi9SNLKzTFjxpipwK402aQVLbpKp15kadXmypUrC0wpBgAACGdaAaXXQ5a7775bPvvsM1m1apU0b968SBXpQ4YMkbvuust8rdXkmoDSxJT2/fVVKQwgdJCEAgAfPFvm6cWTv6tmac+oFStWXHE/rY7SDQAAIFK5JqAsOi2vsIVYvFm6dKn5wM5V+/btJTEx0bQ9uPnmm6/6WAEEFtPxAAAAAABBodXfM2fOND2dBg0a5FZxrhXkOi1PV4+97bbb3Pr6njt3Tk6ePOm1ckpXmt2zZ0/QzgFA8VEJBQAAAAAIqGuvvda0NUhLSzOrCz/33HPOVYa1lYEml7Sqadq0aRITE2P6ZGqz8o0bN0qbNm1Mkkobl5crV67AYyclJUlqamqRVhZWuqqstbJsQFesdeS61H94VtX7iNuitCzfR1xjDj/iNhGbvZC4+4qyvuP2yyuXuMT1/CJuZeFIXC1ZgndOns/rC0koAAAAAEBA7du3z/ypN7ZatfTQQw+Zle7mzJkj7dq1Mz2iXOniLVot9fbbb8srr7xipvRlZWWZaXwJCQlu+2oTc52S54uuxKfJLU/btm1zTgnU6iutqDp48KCcOnXKuU/dunXNpk3Udel5i1ZsaR9PPQc9JkuLFi2kcuXK5rGtm/hyKbmSXqmFOOwxUu7cTrdjuFSljdjysiXh/F5nzGGzS3qVtmLPSZX41APOeF5UvGRUaiHRWeckNu2IM54bkyiZiU0kJuMniUn/0RnPiUuSrPL1JfbSUYnOPOuMZyfUMlvcxUMSlZ2fvMsqX09y4qpK/IXvxJ6b4YxnJDaWvJiKkpCyW2wmoSWSnBwlbdu2NYnB5ORkt3Pq0KGDea927NjhjGmiQvuf6mu4d2/+uep7qe+/Vshp43qL9llt2bKlHD9+XI4ePeqMB/J9UpxTVLHPyfodvxKbw7PpCbzSbLm+wPpmVKxY0e+f++vmNAmWoTcVbU41EI6/UyiI1xJeLX9aIk7fKUF5Gn6nwvN1DOY1VzBxfYdIHZ++/fZb08NJE0i+vPrqq/Lll1/KRx995LxZX7t2ramM8uzF+e6775rFXvythKpXr55Zqc96HQNZjbJg66WIq4QacmM5qoY4J3GN6++yrgR+pfGJSigAAAAAQFBZqwoX5vPPP5ebbrrJ+XW/fv1k0aJFbkkoreLQqXidOnXy+ThxcXFm86Q327q5sm7wPflaec9X3O1xNUGU/xM+jtJLXBM/XuM+WjsXOR5V7Ljr+Xm+hoXFNWnhLe7rdS9q/Krep2LGOScxMV+PX2Bfv/YCAAAAAKAY+vfvLx9//LFkZGSYKo0vvvhCRowYIVOnTjXf12qne++9V7Zv324qMHTKz6OPPiq7d++WMWPGOB9n0qRJZnre8uXLzdc6/Wfo0KGmv5S/N8AAShdJKAAAAABAwOiqd3/5y19MfxvtZaPJpNdff10eeOAB8/0bbrjBVDf99re/Nb2dtMeMTu355ptvTI8bS9OmTeWTTz4xPZ50P21crkkq7R8FIDyQLgYAAAAABEzPnj3N5os2HZ84caLZrkSbJm/YsKGEjxBAsFAJBQAAAAAAgIAjCQUAAAAAAICAIwkFAAAAAACAgCMJBQAAAAAAgIAjCQUAABABvv76axk0aJDUrFlTKlasKF26dJF169a57ZOXlydPPfWUXHPNNVKpUiXp16+fHD58uMBj7dq1S7p162ZWn2rUqJFZxQoAAOBqkYQCAACIkCXQe/fuLQcOHJAzZ87IY489JgMHDpT9+/c795k8ebJs2bJFtm3bJqdPnzarVd1xxx2SkZHh3OfYsWPSp08f83gXLlyQ1atXy9y5c2XevHmldGYAACBSkIQCAACIAFr1NHz4cClfvrzExMTI3XffLb/61a9k1apVzuTS7Nmz5f3335caNWqYfR5++GG59tpr5Z133nE+zjPPPCNDhgyRu+66S2w2mzRt2tQkoJ544gnJzc0txTMEAADhjiQUAABABKhQoUKBWHp6uklKqU8//VR69OghlStXdttHp/AtW7bM+fXSpUtl8ODBbvu0b9/eTM3btGlTwI4fAABEPpJQAAAAEUan2s2cOVO2bt1qkkxqz5490rx58wL7NmnSxHxPnTt3Tk6ePHnF/QAAAIojulg/BQAAgJCjU+tOnDghaWlpEh8fL88995z5U128eFFq1apV4GeSkpIkNTXVuU9sbKyUK1eu0P28yczMNJtF+0mpnJwcsym73W42bZCum8WK63Q/h8NxxXhUVJSZKmg9ruHIdfl8Nf+xf34k73FblIh5XG9xjTn8iNtEbPZC4p5TGH3F7SI2W4G4dd6eUyH1NfAWj46ONj/jGtfXSvf3fN19xQP6PhVy7JzTlc/J83kBINyQhAIAAIgQ+/btM3/qja1WLT300ENmpbs5c+aY6XopKSkFfkZjOtVO6T5ZWVlmGl9CQoLP/byZPn26TJs2rUBcm6BbUwKrV69uKqoOHjwop06dcu5Tt25ds2kT9fPnzzvjjRs3Nv2r9Bz0mCwtWrQw0wr1sa2b+HIpuZJeqYU47DFS7txOt2O4VKWN2PKyJeH8XmfMYbNLepW2Ys9JlfjUA854XlS8ZFRqIdFZ5yQ27YgznhuTKJmJTSQm4yeJSf/RGc+JS5Ks8vUl9tJRic4864xnJ9QyW9zFQxKVnZ+8yypfT3Liqkr8he/EnpvfED4jsbHkxVSUhJTdYjMJrcvS09ubxGBycrLbOXXo0MG8Vzt27HDGNFHRsWNH8xru3Zt/rvpetmvXzlTIaeN6i66Q2LJlSzl+/LgcPXrUGQ/k+6Tatm3LORXznKzfcQAIVzaHa2ofPumnefoPgP5jocse++uvm9MkWIbedPkCD4jk3ykUxGsJr5Y/LRGn75SgPE0k/U59++23cvPNN5sE0muvvSZr166VJUuWuO0zf/58effdd80qeNbNuu7Xpk0bt/2aNWtm9uvatavflVD16tUzK/VZr2Mgq1EWbL0UkZVQ9910OfFH1RDnpDH9Xa5atWpEjE+lKdjjfDDvCYOFe08U9/eKSigAAIAIpSvi6QWh6tOnj0ycONFcJLpeHGpSasCAAc6v+/XrJ4sWLXJLQmkVh07F69Spk8/niouLM5snvdnWzZV1g+/JumH3N+72uJogyv8JH0fpJa6JH69xH61TixyPuqq4JiCU52to8RbXn/EW9/W6FzV+Ve9TMeOc0+W4r8cHgHBBY3IAAIAI0L9/f/n4448lIyPDVGl88cUXMmLECJk6dar5fqNGjeS+++6T4cOHy9mzZ80UoZdeeslMB/rd737nfJxJkybJ22+/LcuXLzdf6/SfoUOHmv5S3AADAICrQRIKAAAgAowbN07+8pe/mP422stGk0mvv/66PPDAA859XnnlFdPTpnXr1lKtWjVZv369mYZnNS9XTZs2lU8++cT0eNIeUL169ZIxY8bIsGHDSunMAABApODjLAAAgAjQs2dPsxUmJiZGnn32WbMVRpsmb9iwoYSPEAAAlHVUQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAACg7Cahvv76axk0aJDUrFlTKlasKF26dJF169a57ZOXlydPPfWUXHPNNVKpUiXp16+fHD58uMBj7dq1S7p16yaJiYnSqFEjef3114N4JgAAAAAAAAjZJNS4ceOkd+/ecuDAATlz5ow89thjMnDgQNm/f79zn8mTJ8uWLVtk27Ztcvr0aenZs6fccccdkpGR4dzn2LFj0qdPH/N4Fy5ckNWrV8vcuXNl3rx5pXRmAAAAAAAAZU/IJqG06mn48OFSvnx5iYmJkbvvvlt+9atfyapVq5zJpdmzZ8v7778vNWrUMPs8/PDDcu2118o777zjfJxnnnlGhgwZInfddZfYbDZp2rSpSUA98cQTkpubW4pnCAAAAAAAUHaEbBKqQoUKBWLp6ekmKaU+/fRT6dGjh1SuXNltH53Ct2zZMufXS5culcGDB7vt0759ezM1b9OmTQE7fgAAAAAAAIRBEsqVTrWbOXOmbN261SSZ1J49e6R58+YF9m3SpIn5njp37pycPHnyivsBAAAAAAAgsKIlhOnUuhMnTkhaWprEx8fLc889Z/5UFy9elFq1ahX4maSkJElNTXXuExsbK+XKlSt0P28yMzPNZtF+UionJ8dsym63m00bpOtmseJmup/DdcqfTcRm94iZnxCx2bzHjTw/4yIOh8NtmqFOQYyKiipwjL7i/pyTPseV4vrY+hzWa+UaV55TIX3Fo6OjOacIPicAAAAAQNkR0kmoffv2mT/1xlarlh566CGz0t2cOXPMdL2UlJQCP6MxnWqndJ+srCwzjS8hIcHnft5Mnz5dpk2bViCuTdCtKYHVq1c3FVUHDx6UU6dOOfepW7eu2bSJerlzZ53xrPL1JCeuqsRf+E7sufnN0zMSG0teTEVJSNktNkf+jXl6pRbisMdIuXM73Y7hUpU2YsvLloTze50xhya3pIucP39e9u7Nj+t5t2vXzlSTaZN3i64m2LJlSzl+/LgcPXrUGffnnPQ5LI0bNzY9ufR90dfZ0qJFCzNVUl8v18RE27ZtTWIwOTnZ7Zw6dOhg3qsdO3Y4Y5qo6NixI+cUoeekCWYAAAAAQNlhc7iWRYS4b7/9Vm6++WaTQHrttddk7dq1smTJErd95s+fL++++65ZBc+6Wdf92rRp47Zfs2bNzH5du3b1uxKqXr16ZqW+ihUr+l2NMj85LWiVUEM7VaTChnMKm3PS3+MqVaqY5JX1O4Xi0fFJk3u8lnCz/GmJOH2nBOVp+J0Kz9fxr5tdr7kix9CbLn/4CSjGp5LB+HT1GJtQ3N+rkK6E8qQr4ulJqT59+sjEiRPNibqeoCalBgwY4Py6X79+smjRIrcklFZx6FS8Tp06+XyuuLg4s3nSm23dXFk3+J7MDbvt8k27G2+xwuLif1xv8D2Pr7BjLGrcSkL4G/d2LEWNc06Re04AAAAAgLIjZO8C+/fvLx9//LFkZGSYKo0vvvhCRowYIVOnTjXfb9Sokdx3330yfPhwOXv2rJki9NJLL5npQL/73e+cjzNp0iR5++23Zfny5c4pfkOHDjX9pXzdYAMAAAAAAKCMJKHGjRsnf/nLX0x/G+1lo8mk119/XR544AHnPq+88orpadO6dWupVq2arF+/3kzDs5qXq6ZNm8onn3xiejxpD6hevXrJmDFjZNiwYaV0ZgAAAABQdnz99ddmlfOaNWuaWSxdunSRdevWue2j7Rueeuopueaaa8zsF53Rcvjw4QKPpT1Ou3XrZu7ttDBB7xEBhI+QLQXq2bOn2QoTExMjzz77rNkKo02TN2zYUMJHCAAAAADwp8DgwQcfNEUGuvjNp59+KgMHDpSNGzdK8+bNzT6TJ0+WnTt3mgVztG+o9gC+4447ZPv27c4iA23Pom1ZtBjhl7/8pfznP/+Re+65xyyIc//995fyWQII60ooAAAAAED406onbaOiq4xrIcHdd98tv/rVr2TVqlXO5NLs2bPl/fffN7NgdJ+HH35Yrr32WnnnnXecj/PMM8/IkCFD5K677jL9SHXWy7x58+SJJ54osHAOgNBEEgoAfNCLoNOnTxeIz5kzRxo3bmzKwG+99VbzqZ2nI0eOmEUStJy8Tp06Mm3aNLdVAovyWAAAAOGsQoUKBWLp6ekmKaW0MqpHjx5SuXJlt310Ct+yZcucXy9dulQGDx7stk/79u3NddSmTZsCdvwASg5JKADwkJaWJi+//LKcOnWqwPfmzp1rPnFbu3atWX509OjR0rt3bzl58qTbz+t0Yi0XP3PmjGzdutVMCdZEVFEfCwAAIJLoB3wzZ84010eaZFJ79uxxTstz1aRJE/M9de7cOXONdKX9vMnMzDSrqrtuShfAsjbrw0L901tcK638iTscjgKPLY5cEY2bLddj8xFXPuN5fsbzrhDP9TN++ZxcY9a56uZ6roXFL5+Se9yqYPN83X3FA/k+cU45V31OYd0TCgBKwxtvvCHjx4/3WrWkq3VOnDhRvvnmG2nYsKGJ6adx2s9gxowZ8sILL5iYlpPrp3IjR440X9euXVvmz59vSsbHjh0rVatW9fuxAAAAIoFOrTtx4oT5sE57POlq5Vavp4sXL0qtWrUK/ExSUpKkpqY699F+UuXKlSt0P290kSrPDwOV9p+yqrGqV69uklkHDx50+yBSF8rSbf/+/eZDQ4tWsmvVvDZK16ouiy6cpRVd+tjWDXq5lFxJr9RCHPYYKXfOver9UpU2YsvLloTze50xh80u6VXaij0nVeJTDzjjeVHxklGphURnnZPYtCPOeG5MomQmNpGYjJ8kJv1HZzwnLkmyyteX2EtHJTrzrDOenVDLbHEXD0lUdv7rllW+nuTEVZX4C9+JPTfDGc9IbCx5MRUlIWW32H5OVCUnR0nbtm3Ne5KcnOx2Th06dDCr1+/YscMZi4qKMr2a9TXUFe0t2s+rXbt2Jjl54ED+uepsgpYtW8rx48fl6NGjzngg3yfFOUUV+5z27dsn/rA5rHQZCqXZcn2B9c3QFR389dfNaRIsQ2+6PIACkfw7FUzaa0D/IdDVN9XKlStN4kgbZLrSRJL2OdB/IFTnzp3Nftow05U219T9tJeBv48VKa8lSsHypyXi9J0SlKfhdyo8X8dgXnMFE9d3iLTxSW+OtWrpoYceMokpbU2gjcutxJSrLVu2mP5R2uZAK6E02XTp0iVzQ+yqb9++Zj/XldQ9K6F0c30d69WrZyrWrdfRbrebTT+IdP0w0orrcbveOvuK6028XkO6VoUs2HrJZRKS5wedPuK2qJ8rkLzFNebwI24TsdkLiXv20fIVt+uFsVt8yI3lzLkqz35cvuLR0dHmtXKN62ul+3u+7r7igXyfCjt2zsl2xXNKSUkxH7ZfaXyiEgoA/FRYqfj3338v2dnZppGmPyXl/j6WvxdSyrWENlL+MYvEf6CDdk4Om0T9fMGZqxeVrufkIx5t07Js97j+X5TNIXkOvQy+clwvpe0mbnO7bLaLQ+w2kVyHze0y2Fdcj1Gvd3McLseYkxO09wkAEBg6zrZu3dqsfnfzzTebJJReE2l7Ak/6oZxWdyhdMU8/GNTrpDZt2vjcz5u4uDizedJ/I3RzZf1b6+24fZ2PN26Pqwmi/J/wcZRe4voPode4j646RY5HFTvuen6er2Fhcf231lvc1+te1PhVvU/FjHNOYmK+Hr/A8/m1FwDAlIHrBZAn/VROb3K1vFxLYAvbz7Wk3J/HCsWSckWpchicU14DaWs/JrGSI8l5DdzPyf6DZEm07Mi7Jv+cJE86Rh2W85Ige/Nq5p+TZEm7qONy2lFBDjiq5Z+TpEvLqJNy3FFZjjry/65Wt6VKE9sZOehIklOOxPxzsqWYbX9eDfMcznOynZYatouyK6+2pEts/jnZT0plSZdtefUk1/qUODk5KO+TThcBAASWroin467SPppaIa4frLlWUCxZssQs9GLp16+fLFq0yC0JpeO+Xl916tQpyGcAoDiYjucnpuMBZa+c3HM6njbR/Oc//yl/+9vf3PbTfWrWrGmqk7R6Sc9L99ObWVdjxowxSaann37a78cKxZJyKx5RVUOReE4r/y/yKqF6TQzK+6Tl5JokDuXxKRwwHa9kcH2HcLt+8qZ///5mqlyvXr3MuPzVV1/J/fffL1OmTHFOodMFWn788Ud5++23zWp62mNT//9f//qXs3eUVkHdcsstJq5T8LQHjTY3f+SRR2TYsGF+Hw/j09VjbEJxf6+ohAIAP2mp+AcffFAgrtUqWs1iJY10P71I8kxC6X7a76kojxWSJeXFjFOqHORzsuWndKI9+0YUEtfEj7e4JorsRYo7vC7Bq4krKUJcE2P5XwSv9B8AUHK059OsWbPkd7/7nUn+awXv66+/biqgLK+88oo8+eSTZqqeVox3795dVq9e7UxAKV3k5ZNPPjFJJ13QRT8ofOKJJ4qUgAJQukhCAYCfunXrZpJEmmDSi6ArlYrrp34WnfazadMmWbhwYZEeCwAAINz17NnTbIXRD+CeffZZsxVGp1lv2LChhI8QQLDwUR8A+En7LWnZuH7apn0MdHrPggULZPHixTJhwgTnfmPHjpX169fLvHnzzKd9uq9+Wjd+/HizYkRRHgsAAAAAIgWVUABQBJog0qlQXbt2NdVN+mncypUrTbNoi/aSWbNmjUlGafm59jXQflBaLl7UxwIAAACASEESCgB88LVug1Y06VaYZs2ayYoVK674HP48FgAAAABEAqbjAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAAAAACDgSEIBAAAAAAAg4EhCAQAAAAAAIOBIQgEAAEQIh8Mhixcvll69ekmtWrWkevXqMmDAANm3b5/5/g8//CAJCQlSuXLlAtvx48fdHuvIkSPmZytVqiR16tSRadOmSV5eXimdGQAAiAQkoQAAACLE+fPnZdasWTJhwgQ5dOiQHD58WLp06SI9e/aU1NRUk6SKioqSlJSUApsmmixpaWnmZ/r06SNnzpyRrVu3yoYNG0wiCgAAoLhIQgEAAEQIrVpav3699OjRQ+Lj403V08SJE018y5Ytfj/O7NmzpX379jJy5EiJjo6W2rVry/z582XmzJkmKQUAAFAcJKEAAAAihM1mM5ur7OxsOXv2rFSsWNHvx1m6dKkMHjzYLVajRg3p3LmzrFq1qsSOFwAAlC0koQAAACKUTr8bN26ctGzZUjp06GBi2tdpypQp0qJFC6latap06tRJli1b5vZze/bskebNmxd4vCZNmpjvAQAAFEd0sX4KAAAAIe3cuXMybNgw0wtKK5uUTs/r2rWrJCUlyVdffWWqo7Syafjw4bJgwQLT0FxdvHhRqlSpUuAx9ef08bzJzMw0m+XChQvmz5ycHLMpu91uNk2EuTY5t+K5ubkmcXaluPa10oov63ENR67L56ueDdR9xG1RmqnzEdeYw4+4TcRmLySuxyV+xO1aylYgbp23vgau9DXwFtfpk/ozrnF9rXR/z9fdVzyg71Mhx845XfmcPJ8XAMINSSgAAIAIs3nzZhkyZIjcd999pupJb6ZVzZo1ZfXq1W773nnnnTJ58mR54403nEmoChUqmGbl2gvKlcY0EeXN9OnTvTYu37Ztm5QvX978v67Wp9VUBw8elFOnTjn3qVu3rtn2799vmqtbGjdubKYB7tq1S9LT051xreLSFf30sa2b+HIpuZJeqYU47DFS7txOt2O4VKWN2PKyJeH8XmfMYbNLepW2Ys9JlfjUA854XlS8ZFRqIdFZ5yQ27YgznhuTKJmJTSQm4yeJSf/RGc+JS5Ks8vUl9tJRic4864xnJ9QyW9zFQxKVnZ+4yypfT3Liqkr8he/EnpvhjGckNpa8mIqSkLJbbCahdVl6enuJjY2V5ORkt3PSyrasrCzZsWOHM6aJio4dO5rXcO/e/HPV5GO7du3k9OnTcuBA/rlqrzCtktOVEY8ePeqMB/J9Um3btuWcinlO1kqXABCubA7X1D580k/z9B8A/ceiKD0V/ro5TYJl6E2XL/CASP6dQkG8lvBq+dMScfpOCcrThPvv1KeffipjxoyRDz/80FQ9+fszTz31lLN5ud4gT506Vfr37++23+23326qpu69916/KqHq1atnGplbr2Mgq1EWbL0UkZVQ992UaP6kaohz0pgmgnUabbiOT6Ei2ON8MO8Jg4V7TxT394pKKAAAgAihCZ9Ro0bJZ599Jq1atfL75z7//HO5/vrrnV/369dPFi1a5JaE0uqMTZs2ycKFC70+RlxcnNk86c22bq6sG3xP1g27v3G3x9UEUf5PeN3fa9w0cvcW99E6tcjxqKuKW43mPV9Di7e4/oy3uK/Xvajxq3qfihnnnC7HfT0+AIQLGpMDAABEiI8++kgGDhzoMwH1ww8/SJ8+feTrr782VRX6qeXzzz9vqqYmTZrk3G/s2LGyfv16mTdvntnv2LFjZrW88ePHmyoMAACA4iAJBQAAECG+//57efPNN01PJ8/tT3/6k9SpU0f69u0rEyZMMH1tGjRoYKbgbdy4URo2bOh8HG1KvmbNGlMNpfvp9Lzu3bubKXoAAADFRT0nAABAhJgxY4bZCqP9onS7kmbNmsmKFStK8OgAAEBZRyUUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAAACjiQUAAAAAAAAAo4kFAAAAAAAAAKOJBQAAAAAAADKbhLK4XDI4sWLpVevXlKrVi2pXr26DBgwQPbt22e+/8MPP0hCQoJUrly5wHb8+HG3xzpy5Ij52UqVKkmdOnVk2rRpkpeXV0pnBgAAAAAAUPaEbBLq/PnzMmvWLJkwYYIcOnRIDh8+LF26dJGePXtKamqqSVJFRUVJSkpKgU0TTZa0tDTzM3369JEzZ87I1q1bZcOGDSYRBQAAAAAAgDKehNKqpfXr10uPHj0kPj7eVD1NnDjRxLds2eL348yePVvat28vI0eOlOjoaKldu7bMnz9fZs6caZJSAAAAAAAAKMNJKJvNZjZX2dnZcvbsWalYsaLfj7N06VIZPHiwW6xGjRrSuXNnWbVqVYkdLwAAAAAAAMIwCeVJp9+NGzdOWrZsKR06dDAx7es0ZcoUadGihVStWlU6deoky5Ytc/u5PXv2SPPmzQs8XpMmTcz3AAAAAAAAEHjREgbOnTsnw4YNM72gtLJJ6fS8rl27SlJSknz11VemOkorm4YPHy4LFiwwDc3VxYsXpUqVKgUeU39OH8+XzMxMs1kuXLhg/szJyTGbstvtZtNkmGujcyuem5sr4sh1eVSbiM3uETM/oaVf3uNGnp/xy8k687zWM9pspneW5zH6ivtzTvocV4rrY+tzWK+Va1y5HmNhcZ1CyTlF7jkBAAAAAMqOkE9Cbd68WYYMGSL33XefqXrSG2lVs2ZNWb16tdu+d955p0yePFneeOMNZxKqQoUKplm59oJypTFNRPkyffp0r83Lt23bJuXLlzf/ryv2aUXVwYMH5dSpU8596tata7b9+/dLuXNnnfGs8vUkJ66qxF/4Tuy5Gc54RmJjyYupKAkpu8XmyL8xT6/UQhz2GCl3bqfbMVyq0kZsedmScH6vM+bQ5JZ0MQ3d9+7Nj2uyrl27dnL69Gk5cOCAM669tbSqTFcSPHr0qDPuzznpc1gaN25spjfu2rVL0tPTnXGtTtOVCvX1ck1MtG3bVmJjYyU5OdntnLS6LSsrS3bs2OGMaaKiY8eOnFOEntOJEyfcHhsAAAAAENlsDteyiBDz6aefypgxY+TDDz80VU/+/sxTTz3lbF6uN8dTp06V/v37u+13++23m6qpe++91+9KqHr16plm5lZPKn+qUeYnpwWtEmpop4pU2HBOYXNOmgjWKkVNXhWlzxsK0vFJk3u8lnCz/GmJOH2nBOVp+J0Kz9fxr5tdr7kix9CbLn/4CSjGp5LB+HT1GJtQ3N+rkK2E0mTPqFGj5LPPPpNWrVr5/XOff/65XH/99c6v+/XrJ4sWLXJLQmllxqZNm2ThwoU+HycuLs5snvRmWzdX1g2+J3PDbrt80+7GW6ywuPgf1xt8z+Mr7BiLGreSEP7GvR1LUeOcU+SeEwAAACKffli5ZMkSefvtt2X79u3mg8ubb75Znn/+ebn22mvlhx9+MBX63u6/vv32W6lTp47z6yNHjsiDDz4o69atMzNUdBV01xkzAEJbyP6mfvTRRzJw4ECfCSgdqPr06SNff/21qbLQrJsOYlo1NWnSJOd+Y8eOlfXr18u8efPMfseOHTOr5Y0fP940MwcAAAAABI5WRsyaNUsmTJgghw4dksOHD0uXLl2kZ8+epk+vJqmsSnnPzTUBlZaWZn5G7wO1aGHr1q2yYcMGr21UAISmkE1Cff/99/Lmm2+ank6e25/+9CczGPXt29cMZNrTpkGDBmYK3saNG6Vhw4bOx9HpPmvWrDHVULqfTs/r3r27maIHAAAAAAgsnaKjhQE9evSQ+Ph40zt04sSJJm61UfHH7NmzpX379qb6SSvwte/v/PnzZebMmSYpBSD0hex0vBkzZpitMNovSrcradasmaxYsaIEjw4AAAAA4A9t2+ApOztbzp49W6SeTLpSuiavXOniO507dzYrpeuCVgBCW8hWQgEAAAAAIo9Ovxs3bpxZMVlXX1baOkV7O2lvKG2b0qlTJ1m2bJnbz+3Zs0eaN29e4PF01Wj9HoDQF7KVUAAAAACAyHLu3DkZNmyY6QWllU1Kp+fpauhJSUny1VdfmeoorWzS1cwXLFggvXr1MvtdvHjRtFvxpD+nj+eLt5XPla4Qba0SHdDVp80q6EVb+dwsWmUe11tcYw4/4tbq7L7inquz+7+au54fq4RzTjaXuOfz+kISCgAAAAAQcJs3bzZT5u677z63Fe1q1qwpq1evdtv3zjvvlMmTJ8sbb7zhTEJpf2BtVq69oFxpTBNRvkyfPt1r8/Jt27aZFfZU9erVTUXVwYMH5dSpU8596tata7b9+/ebBuuWxo0bm6mAu3btkvT0dGdcK7m0F7E+tnUTXy4lV9IrtRCHPUbKndvpdgyXqrQRW162JJzf64w5bHZJr9JW7DmpEp96wBnPi4qXjEotJDrrnMSmHXHGc2MSJTOxicRk/CQx6T864zlxSZJVvr7EXjoq0ZlnnfHshFpmi7t4SKKy85N3WeXrSU5cVYm/8J3YczOc8YzExpIXU1ESUnaLzSS0RJKTo6Rt27YSGxsrycnJbuek1W1ZWVmyY8cOZ0wTFdqfWV/DvXvzz1UTkO3atTMr2B84kH+u2i9MK+WOHz8uR48edcYD+T4pzimq2Oe0b98+8YfN4Zo6g0+aLdcXWN+Mosxb/uvmNAmWoTddHkCBSP6dQkG8lvBq+dMScfpOCcrT8DsVnq9jMK+5gonrO0TK+PTpp5+afr66mrlWPfn7M0899ZSzebneHOsCU/3793fb7/bbbzdVU/fee6/flVD16tUzzcyt1zGQ1SgLtl6KuEqoITeWo2qIcxLXuCaDdSrtlcYnKqEAAAAAAAGjyZ5Ro0bJZ599Jq1atfL75z7//HO5/vrrnV/369fPrHrumoTSyoxNmzbJwoULfT5OXFyc2TzpzbZurqwbfE/WDbu/cbfH1QRR/k/4OEovcdPQ3VvcR2vnIsejih13PT/P17CwuCYtvMV9ve5FjV/V+1TMOOckJubr8Qvs69deAAAAAAAUw0cffSQDBw70mYD64YcfpE+fPvL111+bigqtVHr++edN1dSkSZOc+40dO1bWr18v8+bNM/sdO3ZMBg8eLOPHjzcVGABCH0koAAAAAEDAfP/99/Lmm2+ank6e25/+9CepU6eO9O3bVyZMmGB62jRo0MBMwdu4caM0bNjQ+TjalHzNmjWmGkr30+l53bt3N1P0AIQHpuMBAAAAAAJmxowZZiuM9ovS7UqaNWsmK1asKMGjAxBMVEIBAAAAAAAg4EhCAQAAAAAAIOBIQgFAMZw8eVJ++9vfyjXXXGN6EuhSw7qCi6s5c+ZI48aNJTExUW699VbZuXNngcc5cuSIDBgwwCy3rP0Qpk2b5rbsKQAAAABECpJQAFAM2jwzKSlJ9u7dK6dOnTLLDt91112ye/du8/25c+ealVvWrl0r58+fl9GjR0vv3r1N8sqSlpYmPXv2NKvB6NLFW7dulQ0bNphEFAAAAABEGpJQAFBEBw4cMKu8aINNrXKKiYmR3/zmN9KjRw+TRMrIyJCJEyfKe++9Z1Z0sdvtZvlgXZrYtSnn7NmzpX379jJy5EiJjo6W2rVry/z582XmzJkmKQUAAAAAkYQkFAAUkVZAaaLp0KFDzphWO+3YscMsFbxu3TqpX7++tGjRwu3nBg0aJMuWLXN+vXTpUpOcclWjRg3p3LmzrFq1KghnAgAAAADBQxIKAIpIe0A9++yzpg+UVjZ98MEHZnqeTqO74YYbZM+ePdK8efMCP9ekSRNTQZWdnW2+Lmw//R4AAAAARJLo0j4AAAhHWtX05Zdfmr5PmjTSqqhdu3bJpUuX5OLFi1KlShWvFVQOh8P0gtJEVmH7paam+nzuzMxMs1kuXLhg/szJyTGb0imAummTc9dG51Y8NzfXHMuV4lFRUWKz2ZyP6xpXur8/cZ1uqI/rGtfH1f09j9FXnHMq4jk5bBIll/fJFZv7OfmIR9scog/rGtf/i7I5JM8hkudHXD/dspu4TVxb7NvFIXabSK7D9vOzFx7XY7TZRHIcLseYkxO09wkAAAAljyQUABTRZ599JiNGjJBXX31V7rzzThM7e/as6e2kfZ/uuOMOSUlJKfBzGtOb3PLly5uvK1SoYGLaC8pzP01E+TJ9+nSvzcu3bdvmfOzq1aub5NjBgwdN43RL3bp1zbZ//34zhdCiq/jpVEBNpKWnpzvjOqVQE2b62K438W3btpXY2FhJTk52O4YOHTpIVlaWmZpo0Zt6naaoz6eN3C0JCQnSrl07OX36tOmzZdGVAlu2bCnHjx+Xo0ePOuOcUxHPKa+BtLUfk1jJkeS8Bu7nZP9BsiRaduRdk39Okicdow7LeUmQvXk1889JsqRd1HE57aggBxzV8s9J0qVl1Ek57qgsRx2V88/JlipNbGfkoCNJTjkS88/JlmK2/Xk1zHM4z8l2WmrYLsquvNqSLrH552Q/KZUlXbbl1ZNcq3A7OTko79OJEyfcHhsAAAAlw+Zw/SgVPmmlgV6c6oVsxYoV/f65v25Ok2AZetPlm08gkn+nQoH2bHr00Uflf/7nfwqck1Y2/eUvf5FZs2aZ1e5cff311zJ8+HD57rvvzNd6czx16lTp37+/236333672e/ee+/1uxKqXr16ppm59VpSNcQ5ycr/i7xKqF4Tg/I+aSJYf5fDcXwqy+N8MK+5gonrO0TK9VMoYXy6eoxNKO7vFZVQAFAMmgjwpBUucXFxcs8998iDDz5o+j81bdrU+f0lS5bIgAEDnF/369dPFi1a5JaE0sqMTZs2ycKFC30+tz6Hbp70Zls3z+P0dqzWDbu/cc/HLU5cb/C9xX0dY1HjnJPHMdryUzrRbukdKTSuiR9vcU0U2YsUd3htPKmJKylCXBNj+V9EB+19AgAAQMnjKgsAikin3T388MNmBTud/qPb2rVr5e677zaVTTolbsqUKTJs2DA5duyYqcBYsGCBLF68WCZMmOB8nLFjx8r69etNXymtxtB9dbW88ePHS9WqVUv1HAEAAACgpFEJBQBFdP/995tSU+3LNGTIEFM10apVK7NSnlY3KU02abWKrqCn1U069W7lypWmn49Fp/usWbPGJKPGjRtnekSNGTNGnnjiiVI8OwAAAAAIDJJQAFAMWvWkW2G0okm3wjRr1kxWrFhRwkcHAAAAAKGH6XgAAAAAAAAIOJJQAAAAAAAACDiSUAAAAAAAAAg4klAAAAAAAAAIOJJQAAAAEcLhcMjixYulV69eUqtWLalevboMGDBA9u3b57bfnDlzpHHjxpKYmCi33nqr7Ny5s8BjHTlyxPysrgZap04dsyJoXl5eEM8GAABEGpJQAAAAEeL8+fMya9YsmTBhghw6dEgOHz4sXbp0kZ49e0pqaqrZZ+7cuTJv3jxZu3at2X/06NHSu3dvOXnypPNx0tLSzM/06dNHzpw5I1u3bpUNGzaYRBQAAEBxkYQCEDGf/p87d660DwMASnUM06ql9evXS48ePSQ+Pl4SEhJk4sSJJr5lyxbJyMgwX7/33nvSsGFDsdvtMnjwYBk4cKDMmDHD+TizZ8+W9u3by8iRIyU6Olpq164t8+fPl5kzZ5qkFICyg2ssACWJJBSAsKafzGdmZppP+G+77bbSPhwAKNUxzGazmc1Vdna2nD17VipWrCjr1q2T+vXrS4sWLdz2GTRokCxbtsz59dKlS01yylWNGjWkc+fOsmrVqqs+TgChj2ssAIFAEgpAWHv99dfNNBHtawIA4SbQY5hWMIwbN05atmwpHTp0kD179kjz5s0L7NekSRP5/vvvTcJKFbaffs8bvVm9cOGC26ZycnKcm9VTSv/0Fs/NzfUrrufl+djiyNUT/nnL9dh8xC+/SD7ieX7G864Qz/Uz7vAa13PVzfVcrdfAW9x6311j+vp5e919xQP5PhV27JyTf+cULFxjAQiE6IA8KgAEgV6MJScnS6dOncwn/zExMaV9SAAQMmOYTp8ZNmyYqWLQyiZ18eJFqVKlSoF9k5KSzA2x9oKqXLlyoftZvaU8TZ8+3WvPqG3btkn58uXN/2ujdE1kHTx4UE6dOuXcp27dumbbv3+/6VNl0ebpWoG1a9cuSU9Pd8a1kkuPUx/bukEvl5Ir6ZVaiMMeI+XOuTdav1SljdjysiXh/F5nzGGzS3qVtmLPSZX41APOeF5UvGRUaiHRWeckNu2IM54bkyiZiU0kJuMniUn/0RnPiUuSrPL1JfbSUYnOPOuMZyfUMlvcxUMSlZ3/mmWVryc5cVUl/sJ3Ys/NcMYzEhtLXkxFSUjZLTYrUSUi6entJTY21vxdcaVJxaysLNmxY4czFhUVJR07djSv4d69+eeq0zLbtWsnp0+flgMH8s9Vp2lqgvL48eNy9OhRZzyQ75Nq27Yt51TMc/JcZCBQuMYCECgkoQCErQULFsidd95pLuYUF0gAwkkgx7DNmzfLkCFD5L777pMpU6aY3k+qQoUKkpKSUmB/jemNppUssvbTXlCe+2kiypvHH39cHn30UefXWglVr14901tKpwIq6zgaNWokDRo0cO5rxbX6yqo0cY23bt3aLW69ZvrYlv1bLzmL/DXp5M4uDnucl7hIXnSi13hObBXJia1cIJ4dX0Oy46u7RC5Pf8wqV1eyyl1TIJ5ZoaHHI1yOZ1RsVuAYVXrl69yimpiwkhmu9DXQ73nGraSFa9yaolmtWjW398+K6+qHupqi80gC+D65xjmnop9TuXLlJBi4xgIQKCShAISlf//736aJrvY3sWjzXAAo62PYp59+KmPGjJEPP/xQunbt6vY9vdH+4IMPCvyMVoFolYh1o6n76fQ8rb7w3G/48OFenzcuLs5snvS8PM9Nb/Ctm3xX1g2vv3G3x7W57uN9f69xc4PvLe6ja0WR41FXFbcSEL7+fniL6894i/t63Ysav6r3qZhxzulyPBjXOlxjAQgkRhMAYUeXE//222/lk08+MSXxFm28+8orrzh7LGh/El0J6u677y7wiSUAROIYpivXjRo1Sj777DNp1apVge9369bNJJI0wdS0aVNnfMmSJTJgwADn1/369ZNFixZJ//79nTGdIrRp0yZZuHDhVZw9gFDGNRaAsGxMrvOjdf40AJQ07atw5MgR03fBmjZi0YsinSqiPRa0r4l+rZ/c+foUEwAibQz76KOPZODAgV4TUEqfU6fnaa+oY8eOmWs2nXazePFimTBhgnO/sWPHyvr162XevHmmN4zuq6vljR8/XqpWrXoVrwCAUMU1FoCwq4TSjPktt9xiSrm1D4FrAz4AKAl6YaRTTT7//HPp27evfPHFF85+GfqJ3ZNPPlnahwgApTaGaYXTm2++Ke+8806B7+kUveeee84km/TGUafqaXWTNkheuXKlacJs0abka9asMckoXV1Pe0Tpzz/xxBNXdXwAQhfXWADCLgn13nvvyTXXXCM33HBDST4sABTQs2dPc7M1depUeeGFF0zMtXEoAJTFMUz7uOh2JVrRpFthmjVrJitWrLjqYwIQXrjGAhAWSSgt39QpeDfeeKMzkw4AgfSHP/xBbrrpJtOTID4+3oxDABAuGMMAhCrGJwAh3xPq9ddfl9/85jfOr1lBAUAw3Hbbbc7VW/RCCQDCCWMYgFDF+AQgEEokU6Sl2rpSijawdD4wSSgAQaD95xo2bGj+nwskAOGGMQxAqGJ8AhAIV5Up0tVSdAnfcuXKmYaWcXFxzu/9+OOP8sgjjxRYxvP3v/+9aV4OACXBdVngL7/8slSPBQCKijEMQKhifAIQckkoXda3cePGsnHjRjlz5oxZNcGiCanrr7++wM9o43IACIQGDRqU9iEAQLExhgEIVYxPAEIiCRUTEyOzZ882Dcl/9atfyerVq6Vq1arme7qU77Bhw0rqOAHAafny5aYCU9lsNmfc+n/XWFJSkrRu3boUjhIAvGMMAxCqGJ8ABFqJNG7SweeJJ56QP/3pT/L22287q6QAIBD+/ve/i91uN1OCddPxRqcE33HHHWYKsMb0T92aN2/OBRKAkMIYBiBUMT4BCLQS6x5+zz33yMyZM+XChQtSsWJFlvEEEDDvvPNOgVinTp3kgw8+KJXjAYCiYAwDEKoYnwAEWokuYdejRw+zjOedd97JCgoAAmbu3LkSHx/vXIVTP5XTvnTz5s2TqKioAglyq6wcAEIBYxiAUMX4BCCsklDaA6p+/frm/682CaUlnkuWLDHT+7Zv325KQW+++WZ5/vnn5dprr3XuN2fOHBM7deqUWcHhtddekzZt2rg91pEjR+TBBx80CbLy5cvLyJEjZcqUKabUFED40fFFV9zUccEqFdeVN3VVTqtU3CoXT09P5wIJQEhhDAMQqhifAIRVEqpp06bO/z906NBVPdb58+dl1qxZ8uc//9kkn3Sge+WVV6Rnz57y7bffSmJiosnUa1Z+7dq1Jvm1aNEi6d27t2zdulVq1qxpHictLc38zKOPPmqSWpqsGjp0qEybNs1sAMLP2LFjS/sQAKDYGMMAhCrGJwBhlYRydbVVRpUqVZL169e7rcAwceJEMx95y5YtJjGlX3/zzTfSsGFD8/3BgwfLxo0bZcaMGfLCCy+YmK7epxVSWv2kateuLfPnzzcJMx1krdX8AISXZ555xiSnu3XrJr/4xS/cxgoACHWMYQBCFeMTgEC66vlor7/+uqlG0u3dd991bu+9957Z/vrXvzq3zz//3O/H1cHOc8DLzs6Ws2fPmsbnOrVOq59atGjhts+gQYNk2bJlzq+XLl1qklOuatSoIZ07d5ZVq1YV+7wBlK5PPvnEJJV1Sm7Lli1NpWROTk5pHxYA+IUxDECoYnwCENJJKG1Ud/z4cTl69Kj88MMPcuDAAdNv6bvvvpP9+/fLnj17zPS53bt3y759+4r9PJqNHzdunBkIO3ToYB5XlwX11KRJE/n+++9NwkoVtp9+D0B4iouLk9/97nemsnHTpk1y8uRJk1w+ePBgaR8aAFwRYxiAUMX4BCCkp+NpwsnTZ599Zso4S8q5c+dM0/PU1FRT2aQuXrwoVapUKbBvUlKSSVhpL6jKlSsXup8+ni/akE83y4ULF8yf+imA9UmATjnUzWrQZ7Hi2shPHLkuj2oTsdk9YuYntPTLe9zI8zN+OVlnntd6RpvNrGTheYy+4v6ckz7HleL62Pocnp+aWKtquB5jYXFdmYNzitxzuhquK7To9N1nn31W+vXrJ3369DFjUL169a7q8QEgkBjDAIQqxicAIZ2EmjRpksmWuy7jeezYMXnyyScLLOOplUw6kBXF5s2bZciQIXLfffe5rWhXoUIFSUlJKbC/xvQmV1fBc91PS0o999NElC/Tp0/32rh827ZtzseuXr26qajSTwW04bmlbt26ZtNKsHLnzjrjWeXrSU5cVYm/8J3Yc/NXD8xIbCx5MRUlIWW32Bz5N+bplVqIwx4j5c7tdDuGS1XaiC0vWxLO73XGHJrcki6mofvevfnxhIQEadeunZw+fdpUqVn0fdCqMquKzeLPOelzWBo3bmymN+7atcuskGHRaZKaBNTXyzUx0bZtW4mNjZXk5GS3c9LqtqysLNmxY4czpn9/OnbsyDlF6DmdOHFCroa3FTi1V5wuaHD33XebfnExMTFX9RwAECiMYQBCFeMTgJBOQt10003OCgtrGc8XX3zRWXHhuoxnUZvaffrppzJmzBj58MMPpWvXrm7f0yl22qTck9586825NTDqfjo9T296PfcbPny4z+d+/PHHzYp6rpVQmvXXJufak0pZCbFGjRpJgwYNnPtacX3uLRfSXB718vlnVGzm8WyX90+vfJ3XuCadPOMOe5yX+OUbfE0UOJ/x59e8WrVqbkk3K16nTh2pVatWgWMv7Jw8K2xU69atC1TYKH29XFlx12O04pq08IxzTpF7Tp6J4aL67W9/6zV+++23m/5zOj3YdcVOAAgljGEAytL4pNefulL522+/Ldu3bzf3iprYev755+Xaa6917qd9qDSmH7Lq9elrr70mbdq43/McOXJEHnzwQdMjWIsDdAEq12IFAKHN5nC9Iw0h2mtKqyi05LNVq1YFvq/T7fSmXCs4XAdBTRzpAKQr5CmtZtIk1Pvvv+/cRysztDJEq0j8XR1Pk1B6k63VHlYSyh9/3eyahAqsoTddrtACwkFxf6dQEK8lvFr+tEScvgVbAAQCv1Ph+ToG85ormLi+QySMTzoL5c4775Q///nPJvmkt6Da8FyTTNo/ODExUebOnSvvvPOO/O1vfzMLUC1atEj++Mc/ytatW6VmzZrOe8AbbrjB3PM98MADJlk1dOhQ85jeZrH4wvh09RibUNzfqxJJF48aNcoMApro0f5NJeGjjz6SgQMHek1AKc16a8Zbe0Xp9D/Npi9YsEAWL14sEyZMcO43duxYWb9+vVm9z5oqqKvljR8/3u8EFAAAAACgePTGVO/JevToIfHx8aayfuLEiSa+ZcsWMwVQv9bV1Rs2bGiKCvSeTe8HreICNXv2bFMhpdVP2g5GK+u1gfrMmTNNEQOA0FciSSitRvr1r39t+sHotLlHHnnEa7+motDqpTfffNP0dPLc/vSnP5l9NNmk85L1OXUAe+utt2TlypWm941Fm5KvWbPGZNK19432runevbtMnTr1qs8bAAAAAFA4bcfg2ZpFVzM/e/asqZjQqXVa/aT9Sl0NGjRIli1b5vxaF6nS5JQrvffT1ftWrVoV4LMAEBI9oZT2X+rZs6fZnnrqKTPXV0siNZOtSZ/i0Iy3a9bbF61o0q0wzZo1kxUrVhTrOAAAAAAAJUen4+miVdq3V3uKaiWT9jT1pL1+tThBE1Z6z7lnzx6f++n3Ar3yebFXnzaroBdx5XNblL5QPuIac/gRt1Zn9xX3XJ3d/9Xc9fxYJZxzsrnEPZ83oEko1yZwegBaHqmllgMGDDAVSNoMGQAAAABQtmn7Fm2pkpqaaiqb1MWLF80MFk+6uI3eDGsvKJ3VUth++niBXvm8uKtPl0vJLfLK5+lV2oo9J1XiU/NXmc6LipeMSi0kOuucxKYdccZzYxIlM7GJxGT8JDHpPzrjOXFJklW+vsReOirRmfmrtmcn1DJb3MVDEpWdWqzV3JOTo1glnHMS13Pat2+fBK0xua6Qt3nz5gLxf/3rX3Lvvfeaeb46jS6c0ZgcKFnh2lgzFPFawisakxcbv1Mlg8a/JYPrO0TS+KT3jEOGDJH77rvPbUU7rYT65z//aZqSu9Ibcm1KrlVMWgml5677ea58riuqayLq6aef9rsSSlc+1z5SriufB6oaZcHWSxFXCTXkxnJUDXFO4hrXlkzad/tK41OJVELpAOKNrlygTcv1YMI9CQUAAAAAKJ5PP/3UJIs+/PBD09PXlU6x++CDDwr8jFaAaIWIJqCs/XR6nmcSSvcbPny4z+eOi4szmye92dbNlXWD78m6Yfc37va4miDK/wkfR+klbvpoeYv7aO1c5HhUseOu5+f5GhYW16SFt7iv172o8at6n4oZ55zExHw9foHnkxLQv39/n9/T1ekAoCQ9/vjjzosRb6z5/ZqR1x4CWq2pVZkAEAoYwwCUtfFJK460OOGzzz7zuvp5t27dTCJJE0xNmzZ1xpcsWWJavFj69etn2r243n/q9KBNmzbJwoULi3i2AEpDiSShACCYNDOv2Xad26wZdysbr3G9KNLyUWvTr7V0GwBCBWMYgLI2Pn300UcycOBArwkopX2ZdHaN9orSJFOtWrXM1LzFixe79bHRAgftSzNv3jyz74kTJ8yfulCVTgMCEPpIQgEIO88++2xpHwIAFBtjGICyNj5phdObb74p77zzToHv6RS95557TiZMmGCmF+lUPa1u0ubIK1euNA2YLdqUfM2aNSYZpavracsX/fknnngiIMcNoOT5mBwKAKHtD3/4g9e4logPGjTIufQuAIQixjAAZWl8mjFjhmRkZJjV7Tw3TUBZtKLp0KFDJv7FF194rZxq1qyZrFixwhyHrsg1adIkU6kFIDyQhAIQlrzN+9fS8BEjRpglesNxxRgAZQdjGIBQxfgEIJBIQgEIS56rMuzevVu6d+8uR48eNf0DACCUMYYBCFWMTwDCrieUZso7dOggW7duDcTDA4DzE7nKlSvLt99+Kzt37pQ//vGPpi+Ar+VKASBUMIYBCFWMTwBCuhLqrbfecvt6zpw5Zk5uVlbW1T40APikK7b06NHDrIRy7tw506hSV0vh4ghAOGAMAxCqGJ8AhHQSavbs2W5f66oHSlcqULfccouUK1dOEhISzNKbR44cudqnBACJiYmRX//61zJx4kT55ptv5NVXX5XRo0fLM888U9qHBgBXxBgGIFQxPgEI6SSUJpYOHz4sy5cvl7S0NImPjzfxuLg482d2drYcOHBAjh07Jtddd53UrVv36o8aQJmXm5vr9vWtt94qmzdvlvXr18uUKVNK7bgAwB+MYQBCFeMTgJBOQmnS6aeffpK5c+dKmzZtnGWasbGx5k/9ulatWpKUlGQqolg+E0BJuOeee7wmxZcsWSKLFi0yyXEACFWMYQBCFeMTgJBOQmm5pjYhX7Zsmal4sqbhXbx4UT777DOzjKeFecQASsprr73mNa7LBn/xxRdSv379oB8TAPiLMQxAqGJ8AhDSSSjPxJJWO6kTJ07IG2+8IWfOnHF+jyooAMFQp06d0j4EACg2xjAAoYrxCcDVii6JJTzPnj0r//rXv2THjh2mAkq1bt1ali5dahqTW9LT06/26QAAAAAAAFAWk1AZGRmmSd3rr78ud9xxh2lE7quxHUkoAFdr1apVsmDBAr+m9+r4o2OS7g8AoYAxDECoYnwCEBZJKF0R76677jKb+uSTT8yfVjJKE09DhgwxFVMHDx40Tcxr1KhxtU8LoIyqWbOm3HzzzWYFTu1JpxdKdrvdbNaUXx1v8vLyJCcnp8AKLwBQmhjDAIQqxicAIZ+E0iooHawsWVlZpmGdlZxS//u//yvnz583g1ffvn2dPaMAoDiuv/56s4WChQsXynPPPWcWZahevbrceeed8uKLL5oLNb1Ae+aZZ+TNN98005R1arJWjHo289y1a5c8+OCDsnXrVqlWrZo89thjMnr06FI7JwBlZwwDAFeMTwBCPgkVHx8vn376qfPr2NhYWb58uUlGXbp0ycT69Olz9UcJACHmpZdeknnz5slbb70lnTt3luPHj5uEkyaf9JPDyZMny86dO2Xbtm1SpUoVs9KMTlnevn27GTvVsWPHzBj5yiuvyC9/+Uv5z3/+Y5ZFTkhIkPvvv7+0TxEAAAAAQms6njd6A/byyy8H4qEBwGnKlCkSHR1tNi0Pt0rDn3766YA+7/79++XZZ5+V3bt3O6tBdbWYadOmOZNLs2fPlsOHD0vlypVN7OGHHzbLGr/zzjsyZswYE9NKKZ2ubE1nbtq0qUlsaWJq6NChfvVkABC+SmsMA4ArYXwCECj2kn5AnaKnN06uq+IBQCBookcvjpROgdP+BbNmzQr487799tty7733uk1HdqUVoj169HAmoCyDBg2SZcuWOb/WFUQHDx7stk/79u0lMTFRNm3aFKCjB1DWxzAAuBLGJwBhUwmlzez+9a9/lfTDAkAB2kNp0qRJBRJEgfbNN9/I2LFj5b333pNXX31VDh06JM2aNZOnnnpKbr/9dtmzZ480b968wM81adLEfE+dO3dOTp48Weh+Op4CiFylNYYBwJUwPgEI2STUDz/8IBUqVDBlmlqiqZVQZ8+eNd/TlRV0Osrf//53c6P1q1/9qiSOGQCcY4wn7U0XaLrKp34aWKtWLXn//fdN0kj74Q0cONBMudNG5Po9T0lJSZKammr+X/fRY/W2WIPrft5kZmaazXLhwgXzp5bK66as1Wy0R5VuFiuu47WO21eKa2WrfgJqPa5rXHmujOMrbpXzu8b1cXV/z2P0FeecinhODptEyeV9cuXyqkbO/X3Eo20O0Yd1jev/RdkckucQyfMjriXWdhO3Sf4ZadwhdptIrsP287MXHtdj1MWYchwux5iTE7T3KZLHMAC4EsYnACGbhLrttttMeaZ1Yay6dOliLuA6deokGzZskN/85jdmBSn95P/3v/99SRw3ABRIIijX5Eyg6EVYq1atZO7cuc6Y9nX65z//aRqVa2I+JSWlwM9pTKfaKd1HF3FIT083jch97efN9OnTnf2nXGkT9PLly5v/19X6NDl28OBBOXXqlHOfunXrmk37WunKpZbGjRtLjRo1zGp9ekyWFi1amGmF+tiuN/Ft27Y1r0NycrLbMXTo0MGc144dO5wxvanv2LGjeb69e/c643re7dq1k9OnT5sVBi2VKlWSli1bmmbvR48edcY5pyKeU14DaWs/JrGSI8l5DdzPyf6DZEm07Mi7Jv+cJE86Rh2W85Ige/Pyp5omSJa0izoupx0V5ICjWv45Sbq0jDopxx2V5agjf+ppdVuqNLGdkYOOJDnlyP97XNeWYrb9eTXMczjPyXZaatguyq682pIu+Tc4LewnpbKky7a8epJrdQ9ITg7K+3TixAmJ5DEMAK6E8QlAoNgcrh+lljBtXNegQQPTYPfIkSOmH4pOYwlHWmmgF6d6IVuxYkW/f+6vm9MkWIbedPnmE4jk3ylX+nO6mpxFh7OPPvrIPLaVFA8ErXi68cYb5YknnnCL6/S8Dz/8UPr37y9r166VJUuWuH1//vz58u6778rq1audCQjdr02bNm776dQ+3a9r165+V0LVq1dPzpw543wtqRrinGTl/0VeJVSviUF5nzQRrKtaXs34FMpjWDiN80URzGuuYOL6DqXxe8X4VLIicXxibEJxf68CsjqefkKrK0Xpp5EjRowwMb1B0uknAFBSZsyY4azE1BtMvQHv3LmzuZEMJE1C6aoxjz76qMTHxzvjWpmhU491dbuJEyeagdh1ANak1IABA5xf9+vXTxYtWuSWhNJxU6fiaSVpYSXy3srkrVVsXLlWqbrytfKer7jn4xYnru+Lt7ivYyxqnHPyOEZbfkon2i29I4XG9dfHW1wTRfYixR1eVz/RxJUUIa6JsfwvooP2PkXyGAYAV8L4BCBQSjwJpYmmX//616ZxnX4qr5/0WyIhaw4gdJTW9F6t6vzLX/5ipuC98cYbJumuyaQFCxbI5s2bpVGjRnLffffJ8OHDzVioU+90lRmdDqT7WLThp64kqhd1ffv2lX379pnKUZ2+7OsGG0DkoEUBgFDF+AQgUEo0K/Tjjz9Kz5495YEHHjCf4mvG3LX8nZsqAJFAq1A++eQT04dHxzqdtqNJqc8//9z091GvvPKK+X7r1q3NCjPr16830/BcK6eaNm1qHkd7PGkPqF69esmYMWNk2LBhpXh2AAAAABAYV50V0uknWpb58ccfy+LFi+WZZ54xU1WUVkFp00+tEtBkVLBWmwGAQNNV7WbOnGk2b7SE/dlnnzVbYbRpsi7gAAAAAACR7qqTUA8//LBZWUZXvtMly60ElLr++utl2bJlMmrUKPnHP/5hbrYA4Gr913/9l7OpsDbK1M36f28xnd6mK3kCQFkbw3Q1xW+//dZUZKoffvjBVGl66yun++kHhxZdVObBBx+UdevWmZU3R44cafrh0V4BiFxcYwEI+SSU9Qn+v//9b1MF9f7778vf/vY3qV27tvzud7+TLl26yPLly82y0daKUABwNR566CFzA6XLtGvFkVZjWpu3C6Rrr722tA8ZAII6hqWlpclbb70lp06dcovr41krAF7p57XFgi7AoIsq6ONoz7pp06aZDUBk4hoLQKCVWJOmdu3amWU79YLnF7/4haxZs0YaNmwo27dvl6+++sqs/qRfA8DV+uUvf1nahwAAITuG6YIJ48ePv6o2CLqYQvv27U31k9IPF+fPn2962Y0dO1aqVq1agkcMIFRwjQUg0Eq8nnrEiBHy5z//2Tktr3LlytK/f38SUAAAAEGgbRAuXbokGRkZxX6MpUuXyuDBgwtM7dPVPFetWlUCRwkAAMqigEzq16XJX3vttUA8NAA4/etf/5J77rlH6tevLwkJCXLNNdfInXfeafqXAECoK60xTCuktLeT9obSiiZd5VN7eLras2ePNG/evMDP6gqg+j0AkY1rLACBErDOkvpJGQAEytq1a+Wuu+6Svn37yjfffCMXLlwwvekeeOABGTdunFkMAQBCVWmNYXoz2bVrV0lKSjLtEo4fPy6TJk2S+++/X1auXOnc7+LFi1KlSpUCP68/l5qa6vWxMzMzzXm4bionJ8e5WVME9U9vcV1N2Z+49qLxfGxx5GrTq5+3XI/NR1z5jOf5Gc+7QjzXz7jDa9zqweN6rtZr4C1++ZTc4/r6eXvdfcUD+T4Vduyck3/nFGhcYwEIi55QABBML730knzwwQdyyy23OGO6+tOAAQPkuuuuM401+/TpU6rHCAChNobVrFmzwEIxWt0wefJk00uqV69eJlahQgXTvFx7QbnSmCaivJk+fbrXpuW6OI2urqeqV69uqqkOHjzo1jS9bt26Ztu/f7+cP3/eGW/cuLGZBrhr1y5JT093xrWKS1s+6GNbN+jlUnIlvVILcdhjpNy5nW7HcKlKG7HlZUvC+b3OmMNml/QqbcWekyrxqQec8byoeMmo1EKis85JbNoRZzw3JlEyE5tITMZPEpP+ozOeE5ckWeXrS+yloxKdedYZz06oZba4i4ckKjs/cZdVvp7kxFWV+AvfiT03f8pkRmJjyYupKAkpu8VmJapEJD29vWkSnZyc7HZOHTp0kKysLNmxY4czpk3ndTVqfQ337t3rlnzU/q2nT582q1pbKlWqJC1btjTJyKNHjzrjgXyfVNu2bTmnYp7Tvn37JNC4xgIQSCShAISln376yVzweVOxYkU5c+ZM0I8JAMJ1DGvWrJl8+OGHzq91Kt73339vbnxd6Y368OHDvT7G448/blbTs2j1RL169UyDcz0nZbdfLsJv1KiRNGjQwLmvFdfntSpNXOOtW7d2i+tNvNLHdh7b1kvOIn9NOrmzi8Me5yUukhed6DWeE1tFcmIrF4hnx9eQ7PjqLhGb+W9WubqSVe6aAvHMCp59US/HMyo2K3CMKr3ydW5RTUxYyQxX+hro9zzjVtLCNa4rm1mJBNckohWvU6eO1KpVK/9IAvg+ucY5p6KfU7ly5aSsjU8AIkvApuMBQCDddttt8vLLLxeIa6m6fqJ/6623lspxAUA4jmGff/65XH/99c6v+/XrJ4sWLXLbR6szNm3a5KyW8qTLuusNquumoqOjnZt1Y69/eovrDbs/ceum3DUmtii9W/95i/LYfMSVz7jdz7j9CvEoP+M2r3E9V91cz9V6DbzFL5+Se9xKkHi+7r7igXyfCjt2zsm/cypr4xOAyEIlFICwpKtw3nvvveaTOi0X194l+smd9jTRG6mZM2eW9iECQMiNYT/88INZPU/7QHXp0sX0fpozZ46pgtq8ebNzv7Fjx5ppQfPmzZNhw4bJiRMnzJ/jx483zcwBRC6usQAEEpVQAMKS9hf5+OOPTc8CvVHSUnftr6AXSJ988omz/wgAhKLSGsN0Oo82G54wYYLpa6PTkrZs2SIbN26Uhg3zp43pTeeaNWtMNZTup8fWvXt3mTp1akCOC0Do4BoLQCBRCQUgrOmndL76FgBAWR/DXHvZqJiYGBkzZozZ/OkTtWLFioAdG4DQxjUWgECgEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABFzZJqBo1asjp06fdlhjWlRp0xRbP7fjx424/e+TIERkwYIBUqlTJrAozbdo0ycvLK4WzAAAAAAAAKJtCPgmVlpYmL7/8spw6darAai9RUVGSkpJSYNNEk+vP9+zZU/r06SNnzpyRrVu3yoYNG0wiCgAAAAAAAMER0kmoN954Q6pXry4TJ04s9mPMnj1b2rdvLyNHjpTo6GipXbu2zJ8/X2bOnGmSUgAAAAAAACjjSahRo0bJpUuXJCMjo9iPsXTpUhk8eHCBqX2dO3eWVatWlcBRAgAAAAAAIKyTUFeifZ2mTJkiLVq0kKpVq0qnTp1k2bJlbvvs2bNHmjdvXuBnmzRpYr4HAAAAAACAwIuWMKVNybt27SpJSUny1VdfScWKFU1l0/Dhw2XBggXSq1cvs9/FixelSpUqBX5efy41NdXn42dmZprNcuHCBfNnTk6O2ZTdbjebJsNcG51b8dzcXBFHrsuj2kRsdo+Y+QkRm8173MjzM365V5Z5XusZbTbTO8vzGH3F/TknfY4rxfWx9Tms18o1rlyPsbC4TqHknCL3nAAAAFA26eyUb7/9VqpVq+ZceEqLC+Li4grsq/u59v3VhacefPBBWbdunZQvX960XtHiBL3eBRDawjYJVbNmTVm9erVb7M4775TJkyebXlJWEqpChQqmWbn2gnKlMU1E+TJ9+nSvzcu3bdtmBjql/aq0ourgwYNujdPr1q1rtv3790u5c2ed8azy9SQnrqrEX/hO7Ln5UwwzEhtLXkxFSUjZLTZH/o15eqUW4rDHSLlzO92O4VKVNmLLy5aE83udMYcmt6SLnD9/Xvbu3euWrGvXrp1ZWfDAgQPOuK4U2LJlS7OS4NGjR51xf85Jn8PSuHFj8w/Irl27JD093RnXf0B0pUJ9vVwTE23btpXY2FhJTk52O6cOHTpIVlaW7NixwxnTREXHjh05pwg9pxMnTrg9NgAAACKfLhz11ltvFbrw1JV+XheeevTRR2XJkiXmcYYOHWru3Vh8Cgh9NodrWUQI0+oJHWCsTLkvn376qTz11FOyZcsW87XeHE+dOlX69+/vtt/tt99uqqbuvfdevyuh6tWrZ5qZa9WVv9Uo85PTglYJNbRTRSpsOKewOSe9wNAqRU1eWb9TKB4dnzS5x2sJN8uflojTd0pQnobfqfB8Hf+62fWaK3IMvenyh59AJIxPWiwwfvx4c22o91qu93eHDh2S1q1bm5kshXnuuefMB6gLFy50xn766Sdp2rSp+YBW27RcCePT1WNsQnF/r8K2EsqXzz//XK6//nrn1/369ZNFixa5JaG0MmPTpk1uA5cnLQP1VgqqN9u6ubJu8D2ZG3bb5Zt2N95ihcXF/7je4HseX2HHWNS4lYTwN+7tWIoa55wi95wAAABQdujCU7pZ147FXXjKc/V014WnhgwZUiLHCiAwwvYuUOcM9+nTR77++muTSdes2/PPPy8ffvihTJo0ybnf2LFjZf369TJv3jyz37Fjx8xqeZqB9ydLDgAAAAAIPBaeAiJf2FZCaWO6vn37yoQJE2Tnzp2mwkPnBm/cuFEaNmzo3E+n+6xZs8Yko8aNG2d6RI0ZM0aeeOKJUj1+AAAAAEDgF54qqUWnit3uwrRdKeKiUzpLxjyut7jGHH7ErXYwvuKe7WD8bx+j50dbEs7J5hL3fN6wT0J5tq6KiYkxySTdrqRZs2ayYsWKAB4dAAAAACAUF54qqUWnirvwT7mU3CIvOpVepa3Yc1IlPjV/gZ+8qHjJqNRCorPOSWzaEWc8NyZRMhObSEzGTxKT/qMznhOXJFnl60vspaMSnZm/YFZ2Qi2zxV08JFHZqcVaSCs5OYoFmjgncT2nffv2SUQ1Ji9txW1eF8wmdDSHQzgJ98aaoYTXEl7RmLzY+J0qGTT+LRlc3yFSx6dgLjxVUotOFbcaZcHWSxFXCTXkxnJUDXFO4hrXRLBOoy1zjckBAAAAAJGhJBaeKrFFp4q78I/bAlRFWIzKNG/3FvfR2rnI8ahix13PjwWaOCe73e7z8Qvs69deAAAAAAAECAtPAWUDSSgAAAAAQMgsPKV9bRo0aGCm4PlaeEqroXQ/nZ7XvXt3M0UPQOhjOh4AAAAAIKhYeAoom6iEAgAAAAAAQMCRhAIAAAAAAEDAkYQCAAAAAABAwJGEAgAAAAAAQMCRhAIAAAAAAEDAkYQCAAAAAABAwJGEAgAAAAAAQMCRhAIAAAAAAEDAkYQCAAAAAABAwJGEAgAAAAAAQMCRhAIAAAAAAEDAkYQCAAAAAABAwJGEAgAAAAAAQMCRhAIAAAAAAEDAkYQCAJSKESNGSOvWrQvE58yZI40bN5bExES59dZbZefOnQV+Tr9XuXJlt23s2LFBPHoAAAAARUUSCgAQdH//+99l5cqVBeJz586VefPmydq1a+X8+fMyevRo6d27t5w8edK5T3Z2tjz55JOSkpLits2aNSvIZwEAAACgKEhCAQCC6vjx4zJ58mR58cUX3eIZGRkyceJEee+996Rhw4Zit9tl8ODBMnDgQJkxY0apHS8AAACAkkESCgAQNA6HQ4YNGyYvvPCC1KhRw+1769atk/r160uLFi3c4oMGDZJly5YF+UgBAAAAlDSSUACAoNHqp+bNm0vfvn0LfG/Pnj3me56aNGki33//vZmGZ9myZYv06dNHqlevbqqmtE/U2bNnA378AAAAAIqPJBQAICi2b98uH3zwgc+pdRcvXpQqVaoUiCclJZkKqrS0NPP1ddddZ6bqaV8ondq3YcMGSU1NlX79+pn9AAAAAISm6NI+AABA5EtPT5fhw4ebpuMJCQle96lQoYJpMO5JYzabTcqXL2++fuyxx9y+X7duXdNHSv/URFf79u0DdBYAAAAArgaVUACAgEtOTpb9+/dL9+7dpXLlymbTyiWdgqf/f88995ipeDrtzpP+nE7Ji4mJ8fn4cXFxpp+UVkYBAAAACE1UQgEAAu6WW26RS5cuFWhE/uCDD8quXbvM1zrdThNOmohq2rSpc78lS5bIgAEDCn38EydOyN69e6VNmzYBOgMAAAAAV4tKKABASNDpdlOmTDGr5x07dkxyc3NlwYIFsnjxYpkwYYJzvz/+8Y/y0ksvyalTpyQvL0+2bt1qqqpGjRplqqEAAAAAhCaSUABwlXRlttatWxeIz5kzRxo3biyJiYly6623ys6dOwvsc+TIEVPlU6lSJalTp45MmzbNJFbKKk023X333dK1a1fzmrz11luycuVKqVGjhnMfTVLt3r1bbrjhBvPa/uY3v5Hf/va38sILL5TqsQMAAAAoHEkoALgKf//7302SxNPcuXNNE+61a9fK+fPnZfTo0dK7d285efKkcx+dftazZ0/p06ePnDlzxlT06EpvmogqC7p16+aciudq/PjxcujQIbNa3hdffCGtWrVy+75OuXvnnXdMAk9fQ+0rNWbMGNO8HAAAAEDoIgkFAMWkTbAnT54sL774ols8IyNDJk6caFZsa9iwodjtdhk8eLAMHDhQZsyY4dxv9uzZZiW3kSNHSnR0tNSuXVvmz58vM2fONEkpAAAAAIgkJKEAoBgcDoeZFqZTwFynilkNt7U3UYsWLdzigwYNkmXLljm/Xrp0qUlOudLH6ty5s6xatSrAZwAAAAAAwcXqeABQDFr91Lx5c+nbt69JOrnS6WH6PU9NmjQxK79lZ2dLTExMofvp93zJzMw0m+XChQvmz5ycHLMprb7STftLufaYsuLa9FsTaVeKR0VFmWlu1uMu2HrJ4zMMz/5VPuK2KM3c+YhrzOFH3CZisxcSz/U4Fl9xu4hO3XOJD7mxnDlXpa+BK19xrV7T18o1rq+V7u/5uvuKB+p9Mhw2ifr5dcrV18L1nHzEo20O8za5xvX/omwOyXPou3fluP4NsJu4ze3dtotD7DaRXIfN7d3zFddj1Lcpx+FyjDk5QXufAAAAUPJIQgFAEW3fvl0++OAD2bhxo9fvay+jKlWqFIgnJSWZm2HtY1S5cuVC90tNTfX5/NOnT/faN2rbtm1mhTlVvXp1k8w6ePCgWUXOUrduXbPt37/f9KqyaAN1rcLSHk3p6enOuFZz6bHqY+tNfLmUyzfy6ZVaiMMeI+XOuTdbv1SljdjysiXh/F5nzGGzS3qVtmLPSZX41APOeF5UvGRUaiHRWeckNu2IM54bkyiZiU0kJuMniUn/0RnPiUuSrPL1JfbSUYnOPOuMZyfUMlvcxUMSlZ3/umWVryc5cVUl/sJ3Ys/NcMYzEhtLXkxFSUjZLTaT0BJJTo6Stm3bSmxsrCQnJ7udU4cOHSQrK0t27NjhjGmiomPHjuY13Ls3/1wTEhKkXbt2cvr0aTlwIP9ctcl6y5YtzRTOo0ePOuOBep8uv8ANpK39mMRKjiTnNXA/J/sPkiXRsiPvmvxzkjzpGHVYzkuC7M2rmX9OkiXtoo7LaUcFOeColn9Oki4to07KcUdlOeqonH9OtlRpYjsjBx1JcsqRmH9OthSz7c+rYZ7DeU6201LDdlF25dWWdInNPyf7Saks6bItr57kWsnN5OSgvE8nTpxwe2wAAACUDJJQAFAEeuM/fPhw03Rcb2S9qVChgqSkpBSIa0wrLaxEkbWf9oLy3E8TUb48/vjj8uijj7pVQtWrV8/0l6pYsaKJabWMatSokTRokJ+AsOJageVZYaN0lT/PChulj632e1RCadLJnV0c9jgvcZG86ESv8ZzYKpITm5/EsGTH15Ds+OoukcsVMVnl6kpWuWsKxDMrNPR4hMvxjIrNChyjSq98nTPSwaUSSpMZrjSu77Vn3EpauMat5ujVqlVzew+tuK6AWKtWrfwjCdD7ZKz83FnxpEknt3MShyRIdoG4OSdJd4tbdUjVbBclyZZWIF7HliK1bOcL1MI1sp2VBrazbhVP5pzsPxWohDLnZD9RoBLKnJM9P0EpHX4dlPfJ83cSAAAAJYMkFAAUgVZfaHVK9+7dnTGdAqXJKa1E0dXu7r//flMp5Ul/TqtedCqelWDQ6XlaeeG5nya6fImLizObJ512pJsra/qWJ+tG3t+483F1mpz7T/g4Si9xc4PvLe6jPWGR41HFjru+bp6vYWFxTVp4i/t63YsaL/b7ZA4uP6UT7TndsZC4vk3e4jplzl6kuMNr40mdwidFiOsUwfwvgvc+AQAAoORxlQUARXDLLbfIpUuXTLWStf2///f/TCJJ/3/x4sXSrVs3k0jSBJOrJUuWyIABA5xf9+vXTxYtWuS2j04P2rRpk/Tq1Sto5wQgcun0TR1XPM2ZM8dM70xMTJRbb71Vdu50n1qrjhw5YsYsrSTTKj6dBky/LAAAcDVIQgFACdPpdlOmTDGr5x07dsz06FmwYIFJUE2YMMG539ixY2X9+vVmap/e2Om+ulre+PHjpWrVqqV6DgDCm/aee/nll916jVnmzp1rxp21a9eaflmjR4+W3r17y8mTJ91+Xis7+/TpI2fOnJGtW7fKhg0bvPajAwAA8BdJKAAIAE023X333dK1a1dTRfDWW2/JypUrTVWCRZuSr1mzxlRD6VQ+baCs0/ymTp1aqscOILy98cYbpun9xIkTC3wvIyPDxN977z1p2LChmXqoye+BAwfKjBkznPvNnj3b9BgbOXKkmcqofbLmz58vM2fONEkpAACA4iAJBQBXSaff6WplnrSi6dChQ2YVvC+++EJatWpVYJ9mzZrJihUrTHNxXTlt0qRJzubIAFAco0aNMtOGNeHkad26dVK/fn2zoqKrQYMGybJly5xfL1261CSnXGkSvXPnzrJq1aoAHj0AAIhkNCYHAAAoI/bs2WMWRfCkiyZoH7vs7GyzeEJh++n3vMnMzDSbRZPr1uINurk2g9cpyK79pay4Tl/2XBHSW1yb82vC3npcw5Hr8vmqZ+8qH3FdoMA8rre4xhx+xG2XF0zwGdfjEj/i9ssrA3jErfPW18DbAgWeca1c059xjetrpft7vu6+4gF9nwo5ds7pyufk+bwAEG5IQgEAAJQRWpmpU4E9JSUlmRti7QWl04ML2y81NdXrY0+fPt1rz6ht27aZXnlKpwlqIuvgwYNu/arq1q1rNl3UQftUWbR5ulZgabWprkJq0UouPU59bOsmvlxKrqRXaiEOe4yUO+feaP1SlTZiy8uWhPN7nTGHzS7pVdqKPSdV4lMPOON5UfGSUamFRGedk9i0I854bkyiZCY2kZiMnyQm/UdnPCcuSbLK15fYS0clOvOsM56dUMtscRcPSVR2/muWVb6e5MRVlfgL34k9N79aLSOxseTFVJSElN1iMwmty9LT20tsbKxZndVVhw4dJCsrS3bs2OGMaaJCp3bra7h3b/65JiQkSLt27UyT+gMH8s9Vp4vrwhpaiXv06FFnPJDvk2rbti3nVMxz2rdvn9vjA0C4sTlcU/vwST/N038A9B+LihUr+v1zf92cJsEy9KbLF3hAJP9OoXRfy2COacEUkePn8qcl4vSdEpSniaTxSSso9Ia7WrVq5mvt6fTPf/5T/va3v7ntp/vUrFnTVDJpJZSev+6nN76uxowZYxJRTz/9tF+VUPXq1TM9pKzXMZDVKAu2XorISqj7bko0f1I1xDlpTFfi1cVLImF8Kk3BHucj8fopIq+dEJTfKyqhAAAAygidYvfBBx8UiGsViFaJaALK2k+n53kmoXS/4cOHe33suLg4s3nSm23dXFk3+J6sG3Z/426Pqwmi/J/wur/XuOnD5y3uo3VqkeNRVxW3+gR6voYWb3H9GW9xX697UeNX9T4VM845XY77enwACBc0JgcAAChDCyloIkkTTK6WLFkiAwYMcH7dr18/s3KnK50itGnTJunVq1fQjhcAAEQWklAAAABlhPZmmjJligwbNkyOHTtmpgItWLBAFi9eLBMmTHDuN3bsWFm/fr3MmzfPTAHSfXW1PF31U6cCAQAARHQSShsD6idwnubMmWMaByYmJsqtt94qO3e6N6JUR44cMZ/u6fzEOnXqmKaZrvOsAQAAygpNNt19993StWtXc2301ltvycqVK821lkWbkq9Zs8ZUQ2kTZm2i3L17d5k6dWqpHjsAAAhvIZ+E0lVaXn75ZbdVLCxz5841n9CtXbvWNL8aPXq09O7dW06ePOn28z179pQ+ffqYxphbt26VDRs2eF29BQAAIJJo42OrKbkrrWg6dOiQWQXviy++kFatWhXYp1mzZrJixQrTaFRX5Zo0aZKzPxEAAEDEJaHeeOMNs5zqxIkTC3wvIyPDxN977z1p2LChadSnZeIDBw6UGTNmOPebPXu2tG/fXkaOHGka+dWuXVvmz59vVofRpBQAAAAAAADKeBJq1KhRcunSJZNw8rRu3TqpX7++tGjRwi0+aNAgWbZsmfPrpUuXmuSUKy0379y5s6xatSqARw8AAAAAAICwSEIVZs+ePWb5YE+6vLCu+JKdnX3F/fR7AAAAAIDgoucvUDZFS5jSHgbaNNNTUlKS6X+gvaC0kWZh+6Wmpvp8/MzMTLNZtB+CysnJMZvSKYC66YDnOuhZcV1xRhy5Lo9qE7HZPWLmJ0S0x4K3uJHnZ/xy7wfzvNYz2mwSFRVV4Bh9xf05J32OK8X1sfU5rNfKNa5cj7GwuE6h5Jwi95wAAABQtuh9mi6IcKWevzrrRRdH0J6/2te3Zs2abj1/H330UVmyZIl5nKFDh5pEFH1/gdAXtkmoChUqSEpKSoG4xvQmV5cgdt1Pe0F57qeJKF+mT5/udRDbtm2b87G1X5VWVB08eNBtEK1bt67Z9u/fL+XOnXXGs8rXk5y4qhJ/4Tux5+ZPMcxIbCx5MRUlIWW32Bz5N+bplVqIwx4j5c65Z/8vVWkjtrxsSTi/1xlzaHJLupgG7Xv35scTEhKkXbt25lOGAwcOOOP6qUHLli1No9GjR4864/6ckz6HRT+l0E8xdu3aJenp6c64TpPUJKC+Xq6JibZt20psbKwkJye7nVOHDh0kKytLduzY4YxpokJX4+GcIvOcTpw44fbYAAAAiGza81cXRvD2YaTV8/ebb74xPX+VtlXZuHGj6fn7wgsvFOj5q6yev02bNpWxY8dK1apVg3xWAIrC5nAtiwhhmljSm21rhZfly5ebZYI1K+7q66+/luHDh8t3331nvtabY92vf//+bvvdfvvtZr97773X70qoevXqmWbmFStW9LsaZX5yWtAqoYZ2qkiFDecUNuekiWCtUtTklfU7heLR8UmTe8F4Lf+62XVMixxDb7r84UJEWf60RJy+UyLudyqSBft1ZHxCWRBJ45Pn/d3KlStNEmr79u1u+2lSSu/b9ENWpb19db9f/vKXbvvdcccdZr8hQ4Zc8bkZn64eYxOK+3sVtpVQ3bp1MwOR9n/SrLdFSzJ1frClX79+pozTNQmllRmbNm2ShQsX+nz8uLg4s3nSm23dXFk3+J7MDbvt8k27G2+xwuLif1wHc8/jK+wYixq3khD+xr0dS1HjnFPknhMAAADgb8/fmJiYYvX8LalWK8X+kNcUGxSx1YreG5rH9RbXmMOPuFUE4SvuWQThf9GEnh8fxnNONpe45/NGXBJKp8RNmTJFhg0bZpJMtWrVkr/97W+yePFitylEWpKpU4J0brHuq1OA9E8tA6VUEwAAAAAiu+dvSbVaKW67i3IpuUVutZJepa3Yc1IlPjW/rUVeVLxkVGoh0VnnJDbtiDOeG5MomYlNJCbjJ4lJ/9EZz4lLkqzy9SX20lGJzsxvE5OdUMtscRcPSVR2arHaxyQnR9GWhHMS13Pat2+fRPR0PMuLL74or776qnkx9MV67bXXpFWrVm776NQ8TUbpVD3tETVmzBh54oknzGP6q7glm8EsvaQkEuEkksrJSxvT8a5eRI6fTMcrNsanksF0l5IRkeMTii2SxifP+7uZM2fKP//5T1NY4Er30abkWsmklVB6/rqf3vi60ns8TUQ9/fTTAWu1UtxqlAVbL0VcJdSQG8tRNcQ5iWtc261ooU/ETMfzlSvTiibdCtOsWTNZsWJFgI4MAAAAAHA1dIrdBx98UCCuVSBaJaIJKGs/nZ7nmYTS/bQnVEBbrRS33YVb25UitGAxRRPe4j7aWhQ5HlXsuOv50ZaEc7Lb7T4fv8C+fu0FAAAAAEAQev668tXz15XV87dXr15BO14AxUMSCgAAAAAQMj1/jx07ZqYCLViwwPT8nTBhgnM/bbOyfv160/NXpwDpvoMHD6bnLxAmwmY6HgAAAAAgcmmySacYde3a1dnzd+XKlaYJs0Wbkq9Zs8Yko8aNG+fW8xdA6CMJBQAAAAAIKnr+AmUT0/EAAAAAhB2dgqXLkXtuupT4hg0b5KeffpLJkyebZcu1WqZhw4Zm5TTXlZ0AAMFFJRQAAACAsLNw4cICsQMHDkiXLl3kxhtvlGeeeUYuXrwo//jHP6Rx48by3XffyX333WdWfdLkFAAg+KiEAgAAABARXnnlFRkxYoSphnr88cfN15qAsqZwvfzyy7J06dLSPkwAKLOohAIAAAAQ9s6fPy8ffPCB7Nq1y3ytU/A8paenm1XYAAClgyQUAAAAgLD39ttvS9++faV27doFvpeRkSEbN240K6q98MILpXJ8AACm4wEAAAAIc7m5uTJ79mx55JFH3OLTpk0zzcorVaokPXr0kJYtW0qbNm1K7TgBoKwjCQUAAAAgrGmfpwYNGkj79u3d4k8++aSkpKRIZmamnDp1Stq2bSudOnWSs2fPltqxAkBZRhIKAAAAQFibOXNmgSooT9WqVTOr4tWpU0e+/PLLoB0bACAfSSgAAAAAYWvz5s1y8uRJ6d+//xX3zcnJkZ9++slMzwMABB9JKAAAAABhXQU1btw4sdvdb21efPFF0xPqxIkT5usjR47IvffeKw0bNpTbbrutlI4WAMo2klAAAAAAwtLRo0fl888/l/vvv7/A937961+bflC/+MUvJDExUf7rv/5Lrr32WvnHP/5RIGEFAAiO6CA9DwAAAACUqLp165qG495o7yetktINABAa+AgAAAAAAAAAAUcSCgAAAAAAAAHHdDwAAAAAwbP8aYk4faeU9hEAQFigEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAAAAAAAAAUcSCgAAAAAAAAFHEgoAAAAAAAABRxIKAIrI4XDI4sWLpVevXlKrVi2pXr26DBgwQPbt2+e235w5c6Rx48aSmJgot956q+zcubPAYx05csT8bKVKlaROnToybdo0ycvLC+LZAAAAAEBwkIQCgCI6f/68zJo1SyZMmCCHDh2Sw4cPS5cuXaRnz56Smppq9pk7d67MmzdP1q5da/YfPXq09O7dW06ePOl8nLS0NPMzffr0kTNnzsjWrVtlw4YNJhEFAAAAAJGGJBQAFJFWLa1fv1569Ogh8fHxkpCQIBMnTjTxLVu2SEZGhvn6vffek4YNG4rdbpfBgwfLwIEDZcaMGc7HmT17trRv315Gjhwp0dHRUrt2bZk/f77MnDnTJKUAAAAAIJKQhAKAIrLZbGZzlZ2dLWfPnpWKFSvKunXrpH79+tKiRQu3fQYNGiTLli1zfr106VKTnHJVo0YN6dy5s6xatSrAZwEAAAAAwUUSCgBKoEfUuHHjpGXLltKhQwfZs2ePNG/evMB+TZo0ke+//94krFRh++n3ACAQRowYYXrVVa5c2W0bO3ZskfvaAQAAFEV0kfYGALg5d+6cDBs2zPSC0somdfHiRalSpUqBfZOSkkzCSntB6Q1fYftZvaW8yczMNJvlwoUL5s+cnByzKZ0CqJs2OXdtdG7Fc3NzzbFcKR4VFWWqvqzHFUeu9RM//+nZRN1H3Bal2TofcY05/IjbRGz2QuLWsV0pbtdyNre4np+eq9LXwJWvuE6h1NfKNa6vle7v+br7igfsfVIOm0T9/Drl6mvhek4+4tE2h3mbXOP6f1E2h+Q59N27clz/BthN3Ob2btvFIXabSK7D5vbu+YrrMerblONwOcYgvk+RTBPhTz75pPzxj3/0uY9rXzut7Fy0aJHpa6e962rWrBnU4wUAAJGDJBQAFNPmzZtlyJAhct9998mUKVNMckBVqFBBUlJSCuyvMb3JLV++vNt+2gvKcz9NRPkyffp0r83Lt23b5nxsXbFPK6oOHjwop06dcu5Tt25ds+3fv980TLdotYNOBdy1a5ekp6c74zqlUBNm+th6E18u5fKNfHqlFuKwx0i5c+6VEZeqtBFbXrYknN/rjDlsdkmv0lbsOakSn3rAGc+LipeMSi0kOuucxKYdccZzYxIlM7GJxGT8JDHpPzrjOXFJklW+vsReOirRmWed8eyEWmaLu3hIorLzk3dZ5etJTlxVib/wndhzM5zxjMTGkhdTURJSdovNJLREkpOjpG3bthIbGyvJyclu56TVbVlZWbJjxw5nTBMVHTt2NK/h3r3556r9wdq1ayenT5+WAwfyz1X7hWml3PHjx+Xo0aPOeKDep8svcANpaz8msZIjyXkN3M/J/oNkSbTsyLsm/5wkTzpGHZbzkiB78/KTDAmSJe2ijstpRwU54KiWf06SLi2jTspxR2U56qicf062VGliOyMHHUlyypGYf062FLPtz6thnsN5TrbTUsN2UXbl1ZZ0ic0/J/tJqSzpsi2vnuRayc3k5KC8TydOnJCyzOpr980335i+dkqnDm/cuNH0tXvhhRdK+xABAECYIgkFAMXw6aefypgxY+TDDz+Url27un1Pp9h98MEHBX5GEwqacIiJiXHup9Pz9KbXc7/hw4f7fO7HH39cHn30UbdKqHr16pkm59qTSlkJsUaNGkmDBvkJCCuuz+1ZYaNat25doMJG6WObY9t6yfoJZ9LJnV0c9jgvcZG86ESv8ZzYKpITm5/EsGTH15Ds+OoukcsVMVnl6kpWuWsKxDMrXL5Z9oxnVGxW4BhVeuXrnJEON5ZznqsmM1xpXJMWnnEraeEat3qFVatWzS2RaMXr1KkjtWrVyj+SAL1PxsrPnRVPmnRyOydxSIJkF4ibc5J0t7hVh1TNdlGSbGkF4nVsKVLLdr5ALVwj21lpYDvrVvFkzsn+U4FKKHNO9hMFKqHMOdnzE5TS4ddBeZ88E8NlTWF97XRsIgkFAACKiyQUABSRrlw3atQo+eyzz6RVq1YFvt+tWzeTSNIEU9OmTZ3xJUuWyIABA5xf9+vXz0xx6d+/vzOmlRmbNm2ShQsX+nz+uLg4s3nSaUe6ubKmb3mybuT9jTsfV6fJuf+Ej6P0Ejc3+N7iPtoTFjkeVey46+vm+RoWFtekhbe4r9e9qPFiv0/m4PJTOtGe0x0Lievb5C2uU+bsRYo7vDae1Cl8UoS4ThHM/yJ471Ok05U8+/TpY/7UCsrbb79dnnvuOZOU86evnZVMBwAAKIqwvsqisSaA0vDRRx/JwIEDvSaglN7Q6fQ87RV17NgxMz1qwYIFsnjxYpkwYYJzPx2r1q9fb/quaA8a3VenvIwfP16qVq0axDMCUJZcd911JtGmfaF0iuiGDRtMHzpNjGuFnT997bzRXnVamem6ufar083qt6V/eovreOlP3KoEdI2ZPm8aN1uux+YjrnzG8/yM510hnutn3OE1rueqm+u5Wq+Bt/jlU3KPW9N0PV93X/FAvk+X45dPV3u+uW6+4tbb5BrTPnLmGP2M5znj7o+t+5lj9zNuvU0Fjz147xMAhLOwroSisSaA0qCVAG+++aa88847Bb6nU/S0mkCTTVqtolP1tLpJ+9KsXLnS9POx6E3emjVrTDJKV9fTHlH680888USQzwhAWfLYY4+5fa39x9577z3z5/bt2/3uaxdK/eqU9qyLtH51Kj29fWT1qxORthITWf3q9JzS04PyPu3bt8/t8QEg3Ngcrk0lwoz2JdC+GL6SUNpYU/tvaGNN174GerOn/0gUpaeBfpqn/wDoPxZWzxV//HWz908LA2HoTd4vCoFQVNzfKZTuaxnMMS2YInL8XP60RJy+U4LyNGV1fLrxxhvlqaeeMv8/depU84Gdq6+//tpce3333Xd+r9yp/ep0CrNrv7pArQi5wPSsi6yVO9V9NyVG1sqdGl85PbJW7tR430lBeZ80GazV0pE6PulMF21J4DntfOjQoTJr1iy3mS7PP/+8SZJqP8TXXntN2rQp2HcyVMb5SLx+ishrJ1wVf3+vwroS6kporAkAAHBluiKgVmToTZze4PrT1y6k+tUV6P8WGf3qLh+eLbL61ZkDjLB+ddYBBuF98vX4kYKZLkDkC+ueUK6NNbVsWJcR1uz52bOXS6H9aawJAABQlujN3UsvvWQqCLSyQm/ctB+ULrigN3T+9rUDgGDTmS4TJ040U4j13k8Tc9pPU3t1zpgxo7QPD4AfosO9sea//vUvky2/4YYb5OTJk+bCSi+ktGTcn8aaOk/d35Jy5dpM0J9SZfeS6qKVXxe5pPznBochXX7toyQ5rEvKOadinxMAIPg0ufTyyy+bayf94E4TTw8++KCMHj3auY8/fe0AINiY6QKEv7BOQgWqsWZJNtcsd+5s8RtRFrG5pkiX0G9E2bZt5DXX5JyKdU469QMAEHw65c7bwgqedKVO3QCgNGa66J9633X77bebRV+0kMCfmS4xMTGlctwAykBj8kA11izJ5przk9OCVgk1tFNFKmw4p7A5J00Ga6VipDbWDCYak1+9iGyuSWPyYiurjclLGo1/SwbjU5hgfCoRWsmkM10efvhht5kuhw8fNvdwzzzzjPlgVlcpdqXJJ/0A9dy5c15nurBwQskvnDDkxnLcB3FOUpyFE8K6EipQjTVLtLmmt6aTRW1QWYTmmiHfiLIYcc4pcs8JAAAACPRMl5Ka5VLcmQblUnKLPMslvUpbseekSnxq/oyCvKh4yajUQqKzzkls2hFnPDcmUTITm0hMxk8Sk/6jM54TlyRZ5etL7KWjEp2ZP0MnO6GW2eIuHpKo7NRizdxJTo5iRgjnJK7ntG/fPon4SijNitepU0fuu+8+k3DSF/v3v/+9dO/e3dmYTpfuXLZsmVk1oVatWvK3v/3NNLPTN6AofQ2K+6lDMD+Vi8hPyhCxIv2TvGCiEurqReT4SaVBsTE+lQwqoUoG41OYYHwK6ZkuVEJRCRVqVUN5EXhOZaISisaaAAAAABC5SmKmS4nNcinuTAO3GS9FmP2iiR+vcR8zCoocjyp23PX8mBHCOdntdp+PX+D5JIzRWBMAAAAAIoOvmS6jRo0yBQdqypQpphjBdabL4sWLC0w1AhCawjoJBQAAAACIDMx0ASIfSSgAAAAAQKljpgsQ+VieCgAAAAAAAAFHEgoAAAAAAKCE6IqNgwYNkpo1a5qV4rp06SLr1q3zub9OM50xY4aUBSShAAAAAAAASsi4ceOkd+/ecuDAATlz5ow89thjMnDgQLO6o6u8vDzTVH/BggVSVtATCgAAAAAAoIRo1VOFChWcX999993y2WefyapVq6R58+Ymdv78ealbt65kZ2ebrawgCQUAAAAAAFBCXBNQlvT0dClfvrzz60qVKklqaqr5/+HDh0tZQRIKAAAAAAAgAE6fPi3vv/++bN26VV5//XUp60hCAQAAAAAAlKBrr71WTpw4IWlpaRIfHy/PPfec+bOsozE5AAAAAABACdq3b59cuHBBsrKyZNOmTbJkyRIZM2aMlHUkoQAAAAAAAAIgKipKWrduLa+99posXLhQyjqSUAAAAAAAAAF07Ngx04y8rCMJBQAAAAAAUEL69+8vH3/8sWRkZEhOTo588cUXMmLECJk6daqUdTQmBwAAAAAAKCHjxo2TWbNmye9+9zvJy8uTFi1amJXx+vTpI2UdSSgAAAAAAIAS0rNnT7P5691335Wygul4AAAAAAAACDiSUAAAAAAAAAg4puMBAAAAAAAsf1oiTt8pEkqohAIAAAAAAEDAkYRCwNSoUUNOnz7t/Hr79u1SuXLlAltiYqL06tWrVI8VAAAAAAAEFtPxUOLS0tLkrbfeklOnTrnFr7/+eklJSSmw//Dhw+W6664L4hECAAAAAIBgIwmFEvXGG2/I+PHjJS8vz6/9f/zxR/n000/l5ZdfDvixAQAAAACA0sN0PJSoUaNGyaVLlyQjI8Ov/V9//XUZMmSImZYHAAAAAAAiF5VQKDWaqJo7d65s2LChtA8FAAAAAAAEGJVQKDXz58+XTp06SdOmTUv7UAAAAAAAQIBRCYVSo32gXn311dI+DAAAAAAAEARUQqFUrF69WqKjo6Vbt26lfSgAAAAAACAISEKhVMycOVMeeeSR0j4MAAAAAAAQJEzHQ9Dt3btX/v3vf8vHH39c2ocCAAAAAACChEoolEovqFGjRklsbGxpHwoAAAAAAAgSKqEQMA6Hw2t8zpw5QT8WAAAAAABQuqiEAgAAAAAAQMCRhAKKaeHChdK+fXupVKmSNG3aVB599FGf1V8AAAAAAJR1TMdD8Sx/OjjP03eKhKKXXnpJ5s2bJ2+99ZZ07txZjh8/Lm+++abk5eVJVFRUaR8eAAAAAAAhhyQUUET79++XZ599Vnbv3i01a9Y0sTp16si0adMkkowYMUI2btwou3btKu1DAQAAAABEAKbjAUX09ttvy7333utMQEWiv//977Jy5crSPgwAAAAAQAQhCQUU0TfffCNdu3aV9957Tzp06CDVqlWTLl26yOrVqyUS6NTCyZMny4svvljahwIAAAAAiCBMxwOK6KeffpJZs2ZJrVq15P3335cmTZrI8uXLZeDAgfLFF1/IjTfeKOFKG6sPGzZMXnjhBSlfvnxpHw4AAAAAIIJQCQUUUWxsrLRq1UoWL14sLVu2NF/fddddMmrUKNOoPJxp9VPz5s2lb9++pX0oAAAAAIAIQyUUUETXXnutNGzYsEBcE1MffvihhKvt27fLBx98YJqRAwAAAABQ0qiEAopIp9298847kpGR4RZPTk42VUThKD09XYYPHy7z5s2ThISE0j4cAAAAAEAEIgkFFNGgQYOkUaNGZgreoUOHJCsry1QQLViwQMaNGyfhSBNo+/fvl+7du0vlypXN1q9fP9mzZ4/5/3vuuae0DxEAAAAAEOaYjgcUUVRUlHzyyScyadIk6dSpk1y8eNH8+fnnn5sm5eHolltukUuXLrnF1q1bJw8++KDs2rWr1I4LAAAAABA5SEIBxVCuXDmZOXOm2QAAAAAAwJUxHQ8AAAAAAAABRxIKgFfdunVjKh4AAAAAoMQwHQ/42UvH/xq053q0ztCgPRcAAAAAAKGgzFRCHTlyRAYMGCCVKlWSOnXqyLRp0yQvL6+0DwtAGcfYBCBUMT4BCFWMT0D4KhOVUGlpadKzZ0959NFHZcmSJXLq1CkZOnSoGax0AyLWu28H77mG/y54zxUhGJsAhCrGJwChivEJCG9lohJq9uzZ0r59exk5cqRER0dL7dq1Zf78+WZlszNnzpT24QEooxibAIQqxicAoYrxCQhvZSIJtXTpUhk8eLBbrEaNGtK5c2dZtWpVqR0XgLKNsQlAqGJ8AhCqGJ+A8FYmklB79uyR5s2bF4g3adLEfA8ASgNjE4BQxfgEIFQxPgHhrUz0hLp48aJUqVKlQDwpKUlSU1O9/kxmZqbZLOfPnzd/nj17VnJycsz/2+12s2kTPNdGeFY8NzdX0i+muTyq7ee8X67Hs9l//p63uMrzK37hQq44HA7zvM5ntNkkKiqqwDH6ivtzTvocknb5tbGLQ+w2kVyHTRwuxxIlDrHZRHIcel7ucZUr/sWjL1wI2jllpqSbuOPnt8Omu7qclDPu8TaZuH4rz8941OW/T0F5n9Ivn5Pd5W+e+/t0+W/e5b/R7nHx8jfSV1wHEkcRzyklJeXy66HHWUYVZ2wqyfHJ9bX3Fdf3St8z63HTL16yfqJI49Plvz0OH3GPXzafcWsM9RX3/Jvp/5h79mymOVfl+vfYeg28xXUKQNDG3CK+T0ZaZtHHXJtD9GFd4/p/UTaH5Dn0lb9y3Iw3Jm5ze7d9/XtRpH9Hzp4NyvvE+FS6107F/Tt/eXyKrLFJnT+fE1ljk8bTMiJrbNL4z3/fA/0+MT4xPoXK+BSR106MT0EZn8pEEqpChQrmBdH5wq40poOVN9OnT/fa2K5Ro0YSqv4gkeh/JRJNisR3a/TYYv2YXizoyiZlUXHGpnAdn0JdBP5GRqjg/pvA+BT5107hgPEpXDA+BQvjU2hgbAon/xtS41OZSEJpueb3338vLVu2dIvv379fhg8f7vVnHn/8cbPigkUze5opr1q1qsn2BdKFCxekXr16ZunRihUrSiTgnMJHsM5LM+Q6QOmyumVVccam0h6fgiVSf78iUSS+V4xP4XftFEyR+Hc+UkXie8X4xPhU1v7OR6ILEfo++Ts+2RxloJZTs946UL3//vvO2OnTp6Vx48Zy8OBBM/iE2l9KzRxqmWik/KXknMJHpJ5XKAq3sSmY+HsYPnivIhPjk2/8nQ8fvFeRifHJN/7Oh4cLZfx9KhONyceOHSvr16+XefPmmaz3sWPHzIoK48ePL9ODFIDSxdgEIFQxPgEIVYxPQHgrE0kobVy3Zs0aWbRokVSuXFk6duwo3bt3l6lTp5b2oQEowxibAIQqxicAoYrxCQhvZaInlGrWrJmsWLFCwkFcXJw8+eST5s9IwTmFj0g9r1AVTmNTMPH3MHzwXkUuxifv+DsfPnivIhfjk3f8nQ8PcWX8fSoTPaEAAAAAAABQusrEdDwAAAAAAACULpJQAAAAAAAACDiSUEAZpCuJAAAAAAAQTCShgDLAav32zDPPyKlTp8RutztjQCg5ffq0jBkzRurUqSOJiYly/fXXy1tvvVXahwUXOobUqlVLPv300wLfGzdunHTt2lVyc3NL5diA0sQHPCXn2LFjcuONN0rnzp3l5ptvlg4dOsjvf/978739+/dL8+bNzf/fdNNNsnr16lI+WqD0cf0U+rh+KoOr44WKjIwMiY+PNwkAm80mkeA///mPzJs3T0aOHCn16tUr7cOBj3+YqlevLnv37pVHHnlEPvjgg9I+JKCA48ePyy9+8Qu56667ZPv27ebv7NatW+UPf/iDbNq0Sd5+++3SPkSImPdF3wu9IdQLpqSkJBP/8ssv5b333pN//etfEhUVVdqHCZSoXr16ya5du6R8+fKSkJAgsbGxJq43DFlZWXLx4kVp166dfPzxx6V9qBEhJydHzpw5IwcPHnReL1tJPh1f9Fpa6fug74kvv/nNb2Tw4MHSr1+/Qp/vlVdeMeOXPpdu+mGd/pmdnS2ZmZnSuHFjrzeOQCjg+ik8cP2Uj0qoIElLS5P/+7//k+eff958HQkJqAMHDsh3331nLgT0H+hI+STq/PnzEkn0gvh//ud/zP9rsjA5Odn8g6R/B/nUFqHkgQceMBdQL774otSoUcP8HdVPv9esWWO2BQsWlPYh4md6Q3fnnXfKQw89ZL6+dOmS/Pa3vzU3cnqzBkSalStXytGjR03lzVNPPSWbN2822x//+EdTsaPJEhJQJSc6OtokgPTDs2+//Vb+/e9/S3p6uvN7miSyuP6/K00O6vu2bdu2Kz7fTz/9JP3795ctW7aY6yR9b/VaSW8Kd+7cKcuWLSvBswNKFtdP4YPrp8tIQgWQ63QnTdTooKCJmx07dhT4friwkhZ6YaBJp+eee06uueYaufXWW81Fgn5KGK5OnDghI0aMkIcfftgMDnp+4VgS6ZlY+uUvfylxcXHm4jgmJkZGjx5tLpoLu3ADgk3Hjw0bNsif//znAt+rVKmSTJkyRV566aVSOTZ4pxe7erOmY8vEiRPlhhtukGHDhpX2YQEBVb9+fZOUsOj/t27dulSPKRLp9Yl+KKhtBHTTD3J1vLn22mvltttuK7CvN6+//roZl9555x1TKVIYraiyKqA8WdVRQCji+in8vMj1E0moQLCSS67/YGlpXbdu3czFy6JFiwp8P1zOyfrHWT+Fuueee6RChQomWaNJqCpVqphPnMLR9OnTTeJJ3x/9fz2fuXPnytmzZyVc36OZM2fKs88+a/5/woQJZsBTY8eONZVr1t9DqqEQCr766ivp0qWL6WPgayqMfiJtfRKO0qdTYN5//31TVq4XUm+++WZpHxIQcB07dpTdu3c7v964caO5vkPJT8erVq2azJ8/31RxfPjhhyb5tG/fPvniiy/cPsj1ljjSn9HroHfffVcmTZpk/g0pLBGlSSjdv2HDhtKkSRPTc0oTXlqZ0KBBA3n55ZcDdq7A1eD6KfyU5/qJnlAlzbXXk5buHj582PRJ0moU/Yfslltukb/97W+yatUq+e///m+TAAj1ahTXY/x//+//yezZs+W//uu/5LHHHpOePXvK4sWL5fbbb5fevXvLG2+8YcqXO3XqJOFAL2T0kwO90ND3S5v5Ke0f8Oqrr5rSe52/Gw6sv3effPKJeR/0HyP9+6f9EHr06CFz5swxF1F6sWxND9VpeqH+9w9lp2+ZVov6or+HOr6eO3fO9GNBaNAxUytjNYHv6wIYiARt27Y1fT01OaLjkCajdEzStgS//vWvzbXSwIEDnW0XcHX0dU5JSTHXaPpBro4zehOtN2/Dhw93JqH0dbc+TNPq9XXr1plrHe1XqtfaOkZplbtWhGsPFv3AUact6fvn2ktKf1Z7ZnqrJgFCGddP4alOGb9+4u4zAIkAzTbrBYl++qLTn5588kl54oknzPe1aaV+urJkyRLzj2k4JAD0GLXcXOerakmzJmjWr18vJ0+eNJ9K1axZU6ZNm+YslV6xYoVp0Bnq9PXXaqCpU6eaqicrAaW0+aQ2Wm/fvr35+ptvvjH9HkKZVjcNHTrUNLybPHmyOTdtUqjJNKVTJzURpVPxNJmoibfHH3/cfI9qKJQ2raQsrPJQL7J0fNX9EBr0olbLx7XSsmrVqubfOiBSaV8hXZVNk056M2f1DtIPe/QaSZMeJKBKjo4pOg1Pq6G0ea9eo7Vp08ZUfGhSSr+v9CZON6XTjv70pz+ZD3n1/fr/7Z0JuI3l+v+fTqpjKtJAHLNmKs2GJFOoTFGmE5FMpV9OowYiEUqlIhkqypwISVESGpEhMidFJVMZotb/+tznPOv/7rXX3mvvbU9r7+/nuta195re6XnX8z7v97nv733uueeGl8f4iAi2ChUqhCsFB4lmv0Af58Wv/fv3Z/g+C5EWNH6KP0IaP9lBEOnI999/H6pfv35o/Pjx4ddWrVoVKlq0aGjPnj32/LPPPgvdf//9oUmTJoXigRUrVoSuvvrq0MiRI+350aNHbfvXrl0b+vvvv0OLFi0KlS5dOvTUU0+F1q1bF3rooYdCkydPDmVX2GZYunRp6Nprrw3t3Lkz/B7/d+jQIdSsWbPQTz/9FNq1a5c9L168eGj27Nmh7M4XX3yR4PmHH34YevTRR0OHDh2y57179w7dfvvt9v93331n7bZt27YEx0WIrOpnChUqFDpw4EDU98eMGROqXLlypm+XSJpBgwaFrrjiCrsmcO0rXLhwaOHChVm9WUJkKJzzc+fODT/v06dP6L777svSbcrJjBo1KlSwYEHrX84888xQyZIl7cG4rFixYoRDhWbOnHnM63n66adD5cqVC1WsWDF0wQUXhM4///zQueeeGzrnnHPscfnll6fL/giR3mj8FH8M0vgplP3DcLI5VNMIQvUO/JJatWqVwBSONDwfbUIVFSKFPv30U7djx45sb1Jevnx5i3zq2LFjOESasp+ESaOsMzNFCdB8+fJZlBdhhcwOksqWnSDndsuWLeG0NaqmYBhP2Pa0adPMC6phw4YWck+KIWHcdevWdRdccIF9j3TD7A6VMIIzelu3brV2IAwd8EVYunSpGRgyG0jqQM+ePbN0m4UAfnf0jfwOI8GclmpUOlezD1zr+vbtaxG/RCWQdk4USNu2bXNchVEhglAdLxgZTbGZSKNskX4QLUCUBw/GzIxr/NgGj6errrrKxtnHChYTGzZssPakyA5RU99++61V5+NBtTwhsiMaP8UXGj/9F4lQxwChc5hzQzAf/fzzzw+bVpKa1rx5cxugEAbJ80aNGpknDyG+I0eOzPYm5YhLpBWyj2wzgkaVKlXsogwnn3yymd4R+ow4hZDD/syePdtlp8p3mKaTdudBGKQ8JoIgAxraB48oXqd8JmmV8+fPt9Bv0ikjQ7ezArYzJfjziZQ7zDZpN8RDBFKq/5GCCE8++aS128KFC+072VkMFTmf119/3cxkSScl3YXzEdG0Zs2all4RFPdF1oEvTuvWra2dzjvvvPDrTFTQ53Tp0iVLt0+IjISJN8SJoDF5vPhgxiPcpDF2Se59xi+Mvyl1npKqxvRhXGNSC+NgmTuL7IjGT/GBxk//HxmTp4JIE3HyzidPnmz+OogWwAmFNwDmhogafAehqXjx4iZ47Nu3z6pvFCpUyLyV8FPyZuZBU/PMBG8nBlQYVnPx5oIeDfbd7z+RTg0aNEgQLYX/EFVMKAOKlxKzRpQNRZTLavAU4AeOJ1LQOB3xzO8Hvg74JZE7jSKNkV+PHj1MsSYSipkGTL6zCo75jTfeaKJR0aJFk/2sP4/wssKs0IuIgEEnxwHzcjo7PBSorEFFwOwshoqcD54fDJrwmKPkOTNCFHTgd9ihQ4es3jzxP/AwYPIh2swqnnTcpFP1hVk9IeIdro9MrjEh5019Ga8Rzc6YiWsr4x98GYmwRgghYsdHIIuMheNPO9Ae3GwT4U47+QlUxrTevJzJONqI/xm3ehNzIkX4HpN2tBvf88KX94Xi5hEBivE84zEhshMaP8UHGj8FyOp8wHjgr7/+Cv//+++/hwYMGBBavXq1PR82bFjommuuMe+g/v37h3bv3m2vk9+5fPly++7gwYNDderUMU8hnj/77LOh66+/PjRjxgzLBSXfPavw6ycvdf/+/TG9gY4cOWJ/GzduHFq/fn2C9/CDatu2bejdd98N/fzzz6GxY8eGNmzYEMpsyIl+7bXXQrNmzQotW7bM9hE2b94catiwYejBBx9M8Pm9e/eG7rnnnlCVKlWsTWgj/K3wBaCtgTzdK6+80paRFeedp1GjRqEHHnggxcvo2LFjaNq0aeF29cfik08+sfNSCCGEEEnDddNfO0X2A6+mxYsXZ/VmCCGESAVKx0sBPvrnueeeM38g8tBRl6Fbt24WPUJ6Gil4RNEA+Z1UwqOiHOlepIIxU8MsDbMqs2bNspkWwiRJ+2KWJTNSoVhHcD3MENWuXdu29fnnn4/5fWaGiApiNqlEiRIJ3itVqpTr2rWrKfBEERE1VK5cOZeZ4HVE+V1y+seMGWPVUIhqev/9990tt9xiJTDx8UJlBtIH2XdmzJjtZKYLXyX8HlgW0W6wbt06i+xi1iyj28kv3593Qd+xQYMGWdU7Isxi8cEHH9jnSCcEzlMf5casrfLDhRBCiOThuplUhLjIeohu9+McIYQQ8cFxKFFZvRHZnXnz5pknECl0gwcPNtEiCOGPCBwYWftysD6tzeedk/ZEWlT//v3tOV48HHpEjsxKVwumE27atMm2p0CBAratCBak0b3wwgtmLh6ZeujBy6pTp04WjhytFHFWpRR6CKkmlLFJkyZhsQ9DcszSCUdlu8eNG2cpbQMGDLBwVR6IZffee6999u233w63MeIVbVasWDFLY+NziG0ZRfC4f/jhhxZWS8j4iBEjTLQE8ogxz5wwYUKyy6J8NB5S3rdMCCGEEEIIIYTISiRCxQBxBtEFM+e7777bXkO08UILETcXX3yxRdzkz5/ffHaiVdwgegjhCdM4csmJGAp6KmUkQWGDSiKILTNmzDDBpVatWiaWEa314osvmoE3+fFJQS490UNEC3lRJLtArj5RWKNHjw5XqmF/aDt8j3jPez/hgUVUmjfr9pXjaEMER44Tvl78xScKM/nMYtu2bWYcjtBExBL7RTUebypIVBYiGcbv1113XaZtlxBCCCGEEEIIcSwoHS8GpN9hBk0kjBdhEG0QdTCsHjVqlJkhUhaTlDv+9/gKHXfeeacJB1TJw6wcI/PMEqDAC1D9+vUzMYVytg8++KCbOXNmuOIbEVGIHmw/ZtbgjayDYNrI97ObAOW3l/2jjTyk2RH9VLp06fBrRD4hMO3ZsydBxZUWLVpYGh4G7XXr1nWXX365pehlpgBFyifrxeCedXNeEZk2ceJEM5AnMortQWTr3bt3pm2XEEIIIYQQQghxrKg6XgwQnxBdyDlHDPBpWlS8Q4CiKh7pXzjdt2zZ0kQCooyosuErcpBOhd8S30WEymyIBsK7iu2ZNm2a+VVBmTJlbNtJVWvfvr1VR2vatKml5OFxFS0dD7JrBTWimKjKR7vMmTPHUuemTJliEUS0B6mR/KVSHpVTiHii+oD3EqB9iGojOoplZIaf1caNG+34e1GPan2IlVS5AFI8qTiIMEUEF22COIXnFu1F9BptK4QQQgghhBBCZHeUjpcCSFUbOHCgeQEhRJFWR5QTnkKkpXkwF3/22Wet/OKuXbtckSJFEqR7ZRZEXRHhRCqX93HiuY8GIoILYQPjbVLvEDQQQzAoxwSb9DX+x1Q9KW+o7AwG4hhyYxJPuiHCFG2FDxQRRYhRzZo1s2g0PKMQgRB0EKs4VqS/IVRlhtcYKYC0RYUKFew1f7zZfgQmtgVPJyKzIs8jUkW7d+9uZulFixbN8O0VQgghhBBCCCGOBYlQKQSTaCJnSOHCkNunaCEaIDSRpgYIH4hQfI6oo6xg2LBhJmDgexQ0C0d8QXRChCLljIibU089Nfw9hDX25Z133jFfJfyreD8ehSggLY+KhZUqVXKtW7d2S5YsMR8sRCn8ve666y6LTFu/fr07cOCACVaZDSmAl156qaUH+nOI7b7tttvM5P6hhx6ytvORUghXq1atMk+xk046yaLvEBFTUtlQiOwGwjBppkQApob0LIAQbVm+sERypOQzKSGp/jW5faS4RVZE1WYm9IMI7/F47RHZA/Uv6l+yM8E2yOqiPiL+UP+W9f1bdv3d/hkn46fsvXXZCEQbolYwFcckGnNufwJ68YAIqerVq1vVuawSoPhBImBQcY9Kfv41wPNpwYIF7tZbbzWfKqr9wY4dO0ykITIKYYN9IBWNanmQHX9gsaBdEJ3YV9IOiQpDuMGgHBCe6ISIeCIdLyMFqGg6L1Fz0LNnT/faa6+ZWObhfMITivbgfy9AEfWEmbrvXIA2fvXVV93ChQszbPuFiAUVJdNikk+aM5GAqYUJASqLHit44NGfRxOHEYFJz+VBn86D9GXSds855xwrOJEa8KYjNTra62vXrk30Ov2W9+yLhBTx7777LuY6ie4kWpc+jpReHpUrV7bIXg8p5aT9RsKERFLgq3f48GGXHlDMg+qxkVD9M6lUYyZJon1H5EzUv8RG/UtCmET1lYGxxAiOsRgHY7WBNQUZAox3+UzZsmXtOccMiw3GZikB24eGDRvauJv2w0uWNmSymkj1pOAc4/hxzIjWDzJ//vxwNoPI2ah/y579WxCKkO3bty/R6/RvBAfEuueL9Fgmu2VexPdy4/hJnlApBMX2pptusv8RN/BQ2r59u71OB0KEESf9+++/H/ZcymiiKcA8L1iwoP3Yx40b5zp27BgWm/AZQmBC3ODiyGf5DOl3vOdTwkjtwoydiK4OHTrYfsUbCGdEGLH/RA4h4HjRBkNvZg7Y/8xQsf3yvahEJ4zYh1CJ8TgdG50C/2MQD1THYyDDuUZqJx0GUWksA78uP5NAB8x36fCFyMiUZH43H3/8sUXeIZ4GhVvO55TOuAR/c3wvcjYMsZhBPcvjRoUHn+d8R1R+5ZVX7HfkCz8kBYLz5MmTTbClr/QP+jp/Y8By/CRCkKlTp4b/Z/1ETyJYc/OSFhgMESXrC1wEYf/xqIuE7WLyAx87hGiOBwI0AvbWrVvt9VgwQPXHmu0n7Zo+JnKQFG39tC/9Dsc8EtqICNOUDGRXrlxp5wuedgxIuVYG04eT6n95nahcbh7Zd57TfrQ7EyeZWTBCZCzqX9S/pKV/IYKcPsLf4NFmPPxNqd82/nIueGrWrBn1hjZI/fr1ox7PSCZNmmRjN84bRDgP28H5zBgaG4igdQfjOs551oEthD8PKVrEOJybdLY3JW0gsj/q3+KzfwvCPST3j5GiG8cnslAX9i6sh3tvjhmZNlQ9Z70e2uT4FESC5fTxk0SoNICCSUdyyy232AWXH0f//v1d1apVM3U7OLE4wfhhI0Lg4/TDDz+4Hj16uB9//NE6C6rgDR8+3D6PiMFFb+zYsVaFDfNu1F1SvjjJgx0c+4JIEo8ClIe24QLPMSFKbfny5XaBb9y4sf2YMwtEJPy1CAGlw8KDiplDOoRBgwbZ/8yCIDAhjnlxkYsA7cDsGul2zLTRsfoBnr9oRRvECZGeECnJbwaRnYtimzZtrH/wA2vOy8iZnhEjRrj//Oc/NnDgvGcAQF/J7Ay/R4hWZfOll16yh5/NJhWaQgFBWB9+aclBkYi+ffsmmrl74oknws/ZruQGAlywGXwgCPt+hFnE1ArXTFSw/1988YXdqPjfuP8bbRt4nb6dGcQgfIcbtJRsg/8Ms370Q3jN+UIMQaK1A9uU1ECNwW/wpi4pSAGn2AWFPJjVZxBH9ASz/NG2Mwj9HN8lvTwSrmFMLoicgfoX9S9p6V/wYOWBPyZt+NZbbyXYv+ANcnLtwI0y+x38PDeMKSlOQ5tzvgYFKL8+xnX4j/KZoAjFOc4kNuvjc5wHtB/RXzzHezbWNov4Qf1bfPZvHo7V119/HQ4SCBJNhKNfo1/y7btlyxYTHd944w07BgSK0GeeEKPKfG4YPykdL5V4AYAw3dmzZ1tUCmpjZgtQgKKNEEZOMNFMhDfSsSFKMNPCictffrgeZlgQlhCemA3avHlzWIDix+lPZn4khCfHO+wr4dV4ZNWpU8ctXrw4UwUo33FzISFljvOGzghfMS5EKPUMttq1a2cXCtoyKC5x0aKzaNKkSbizo438Q4iMBg85ZrgZlJDCyizP448/brO/Hi6mkbPfvMYAnIstNyekAzOoChrsxxpkcyPgIzmDpKTYQ7SZRSpLBvtq1h9tWdyU8NsjcpTBDxGj9K2klfAaM32IyikdwJCeQtg2v3ugbyYFg76IGfmkUnaj7YN/Lbl0lkhoKyIw+/XrZ8/ZN55feeWVdkyitQPth3iOaE4fSqoK1wRukIIznbEGjxwv+jmOM9coCmdwPjFxQtoxg9qkBlHJEWsmV8QH6l/Uv6S1f/Gwj0QbRO6HX2+sqANu6kjR8VCghmgBtikW2F9ww8lENBFYfJc25cYTIYE+kMyCIJ06dbIxOzeZjAuJkEGAIvuA8R7HjTGhxnjxj/q3+O/f2H6irYhoBIQ0Mm2IiooUhPw6IreJ40Q1dvoIL6blidEOuWH8pEioVOJD2rjA/vbbbzGVzIyEzgnFm06NtDOim7jwcfECUrVQ4PkBE54JKLm8z0UwUtXN7gZmaSFfvnzu3//+t6nxmd1WPqqMMEp/IShRooR1RIRds110MkCHTMfMzBnh215wIrotPU38hEgtS5cutQthZDQo4eUezvPIi15S/Unwwhurz5kxY0bUQVRa+ioG+eTPEwEa3O7I3xWDF/pUBh0MHBGvgRk1bhhmzpxpgyEGVEwExILfMwM3+mpm4NgnPPl4+D4hchYUCLlmksNHBbDP7AMPBnYphWhLBsKI4cyMUZDBF6gARPFox5NtYhaNmbdISEdPSU0TIm0ZrHk41lw7KZrBwJr1EqkbbVaOvpsBHm0RKbxT+CPyxk7EJ+pf1L+ktX/x4NXKTTrQ3xAxwj7goZkSEYr36G88/M+4LSUiEDfDRElwo3rvvfdaFgLbzsQj4zmOS2Q0BjAOxzZjzJgxtj6OI6IcxXO42cR3Nj18e0TWov4tvvs30uiIQGLbGXMQHIDgzAO4946E+7Vo/Rded/RNHDPEteNi9C+5YfwkESoN+B9wVgpQqL+cYP4iVapUKftxEO6HSkx003vvvWfhyXwWkzLe58fhK+Lxv88VzckUKVIkS9brjyvRTZhcevWd84YZMmb9CCNHXWfAgxE8swV0uHS2QSRAiayCfPzISiJnnnmm+/nnnxOJ8ymZaQlenJMbDHHRZ1aZQQAh7AzYj4UXXnjBZp9Ib03ut8U2EUGaFFy8ebAfDGiSShth/wmd37Rpk4XE58+f34RmUoSJQCVt2hNtwMLNy7HAbBnp2KR9ELXr14+PCjNrXD+izcB6vJ9EtP0K/k0OJmoijzfnEqJ7rIEw1Vt5iJyN+peEqH9Jef8CRBNxY8o5ws0ZghT/sy3c8Ea2AzeU3AQzCcuDbeSGkHRC0mf8Taq/kWQyN1bhF26wEaB4pBSiIRjzca77iCqiPYYMGWKTk2xP0PtFxCfq3+KzfwOOHd5JZNIQdUQRKNbP7zOYUROt7Xz/EfRiIjqM/oc+J1goITePnyRCxSF+lgV/I8QlZp6ACygnNjNQnOjMqOArxMn6yCOPWOoeHYb/YUjYyFh8vjKpdPg5EX6NOu0N64jOYlaBtkFEBAZQtCkDn6wSz4SIHGB//vnniWZ0vJid1ExeUuHOwdeTEsAZPHXu3Nku/vRn/Fa4qQmmV6QG0nCZdcN3LUjkdiPYM/PE75SBArOORCUyc8R2cywYOHHTwjYygGJAFA22nZsiZvwYQAEGnYS0k8IdJDiIIS2E9fEd1o2/gJ/F4zkmpzy4+WI7mAmLZjLJd/CYY8bdHzduupik4Pt+EiWpm0T6KMLOSR1gWczwc1PkB1fRquJEghkpN1NB2Lfk+jaEeGaJEe7Zdz/zu3//fmsXb/TpbxQZXDP5IuIT9S/qX9LavwAeK9wYXnjhhRZBRJQ5cDyD6/b/c/PKI9YkMuO0pCIaPEHLCrafffIRVRw7jjNjO38TStt4YYnKfUwMYyTNOmhPqoohZDGJzDmlSKj4R/1bfPZvHK877rjDxDefkYK4jp8S0Ztsly9CFtl2RGcRweWjj1g/qb1BYYhlHo2REpgrxk8hEbdMnjw51L59+9DOnTvDr3322Weh1q1bh7Zs2RJ+7dChQ6H69euHHnzwQXt+9OjRLNnenMjff/+d7Pt//fWX/W3WrFmoXbt2Cd7r2rVraOjQofb/n3/+aX+XL18eKleuXGj27NkZts1CpIZVq1aFSpQoETpy5Ej4tenTp4caNmwYfv7xxx+HqlSpkuB7L7/8cihv3ryhf/3rX6Hy5cuHSpUqFSpQoEDo4YcfTtCH3XbbbQm+t3fv3lCtWrVCvXv3tues97rrrrPP+d/JwIEDQ7169UrR9o8fPz5UoUKF0Jo1axK9t2LFilDt2rVjLqN///6hbt26hVJL8JglRZcuXUK//PJL+Pnhw4cTfWbhwoUJji/9Dp/7448/jrk/nzNnTujXX39N9jObNm0KnXLKKale9tSpU0ONGzdO0B+eeeaZoe3bt9t5Ubp06dBpp50WuvPOO2Mu68ILLwxt3rw5wbK4th08eDDV2yWyD+pf1L+ktX8ZN25cqGzZsqHdu3fbsahatWqoX79+9t4bb7wRatOmjf3PmOr7779P9P358+eHunfvbu1/ySWXhGrUqGHnwcSJE8PnQkqhndnX4LJr1qyZ7HcWLFhgY8Bhw4aFlixZkuC9L774ItSiRYtUbYPIfqh/i8/+bc+ePVH3OZIOHTqE3n///VBqGT58eGj9+vWh3D5+ynkmQDkAVFWUWoiW6+ohTI/QPF8JAZg9IgeZFDBA6URtJkSa/HufjyqOHULA8UCAWP4FzA4S5YQxOaGxgEJONBv4sHXyfcmjPtbQWSHSCyqbcF4ys0a/gvcGEZbB1APO3cjfALNI+/bts1TT9evXm18dszHevNZ/LwipHUR00o8xQw7M5DDzxbq9fwjfizWLxEwWs014blBSmHDqSOgfo/WxhNAz45bc/qUEtp19phAE+4R/CLN5/OU3TnQqvn3MeHm8HxzRrJjjgp9J99B38DlmtmL158z2EW2JNwCVqzC95S+h9RSnIOQ7VtQl+5GSalWRkF6Cr8Ho0aPtmjZgwABbN5VbOS+YBeV8SIlJaOTsLbOLKmMe/6h/Uf+Slv6FbcfWYN68eRaBxDKIAiDKxEcy+WPq02OCEDVFpBH+PNhWfPbZZ5a+x1iZSsr4yRCtkVKipcfEijjhWJGWRSRCly5dzIaBtiOahNeoiiziG/Vv8dm/nXLKKeF9JtqSSMdoEFEVbd+INmK8Q/9CX0J/yO+a7ScKkgjJ8jGKf+WG8ZPS8bIZXEDJVyfnE3EpubxP3PH5AVJljR8hIclUQ8AIzpeG9D8wXiNHNvhjFceWZkeKXePGja2ySY0aNcKvB+E5nR9iIcbxDJIw9yNUknDcYEUWD20qRHaCQTqDGi6KnLdclDFdTW6QkdTFPXgxjBzAkIZK3jzVkoKQ5oHviL/BiDWI4gaEGwo8BUiHjVWaOxLSmhko+oEU+xKtFG9KYBuoNspALmh+yz4Q5s724aEQWQ4cwbp+/fqWvkHYN4UM0gJVeAi9ZlAZWY2FgRWDJELFfV/EMWF/g+3E972ZJ8eLB5/zFamCqQVBOGZ4E5J2w/WMmy7C2SP7yLQMokTOQf2L+pfU9i9sd6RXE+k+voJWMB0v8iYUqEbMcaFitIfJQAQDHqQeIXAxxksJkeent71IDrYVoYF1BY8d2076E21C2o+Ib9S/xW//BnhAJXVfRjptNDGJFEiELI5jpMCOeMR2FylSxMSppMgN4yeJUNkIflSctBhTI1RQcQPFN5q4AbzG+1Qi4QeHeRviFWU8o30+0uxaxMYPJPzfYJU6jnGZMmWsg0DgS0ow9J/nokNOMUZ7DDxou3joJIRgEICJalL4G4fUwsUz8uYgcgAV/H34Si/8HpNbHzcTlM2OBTc+0ZbDbzY4cDgWbw5m8hCdI/eT/cG3gH2JVq2F/sT3KdzEMdhJCxwLDDa5ofMFEoLrYF+Ds2FMakyaNMm2jQo3wDZyPBjQ+WPvH3we34SkINpz8uTJSb7PMhj0ityL+hf1L2ntX5KCPsUf+2iRUFTto8JV3759XcmSJcOvc6y4kaf6NGJUatYXJCWRH4gDy5Yts2goohuC32V53A+I+Ef9W/z2b5DcsSLKKRr0edyPe++ryG2H41OQlZTTx08SobIBXtjwJyYV0wgHxok/VjQUMNPEg4GAN0oT6YMXngiHJfLMG7sjPKGOYz5HmiMVTTCTjDX7RVsGVfOgqCVEvJLWcGvO/7RcQNPrwsvgJdrvlWUzy04VG2ao/Sw16/Wz9oj6REHGghl3Zry56cEck2X4foTB0euvvx411J1tINqSGzV/ffDh77yHqS03ULFgAEj5b64RrJ/1+j6HwR0zlsFKL2zPm2++maYyzmmBfUrJTB5tkZUVaUXWof4ladS/RIebTn/jGa2PId2NyV6M1Unb8Te5tAUThAhRTDKmFL4fbOuUnLOk/iFEtW3b1lKpfMVq2oQJS+4BRM5H/Vv27d+AdWG94tP3+I3yGstjX0gNjPytIuKRTkvEE6l0fN7briAUsk+VIwIRcuP46TiMobJ6I3IrhBByUvjUufHjx7uBAwfaD4oSlrNmzXI33XSTa9myZZLRUBApfEjYSF8QmMgvpvIDEWfk5dKB0lZ0JgsWLLDqCuTo+pkGIXIT/DbWrl1rHiCZ5cdGaDmD92MhKdHYDwqTu1Hiwh+ZfpKexOrzY21fvMBMIYPLpFL6hFD/kv7klv4lq8ALC/+flFb5E7kX9W/pT27p3/6I8/GTRKgsAsECs7Wzzz7bytzyP2opymy9evXsMxjZMUMzceLENJnCirRdDIoVK5ZAyCPMvFq1ahZpRhlgoqDw2ALUfsph8hnM//AkUFqdEEIIIYQQQgiRmPiXAeMA3PNJrwOv+ZGDjkkdZmtUICDa6fPPPzcBateuXa59+/YWDowZGgJUWvKFReog5Y6Kg76CoA/PJgQT7wDye4l6QoBCrKKNqM5ASh4VCQl39AIUhpyo00IIIYQQQgghhPgvEqEyGIQIPIMoJYv5oM9LBSKgqBhCuUbKcQJ5oqTjYWpGeGbz5s3tdcIGCZ/01UAUwJZ+kIvvDeA43r169bLnwVBN31a0E0bwlCP+6quvLA3Plz0NVkXAXP6HH37I5D0RQgghhBBCCCGyLxKhMggM10ilI4qJEozka1K9DrypWuHChS0HGFEKIQOTMkpaIn5gZhYsaYlfFKlgI0eOtKgopXwdO5S+pPoJlVq8SR8CE9Fpa9asSSAYeqM5Sq1iHE81PAzx+MyECRPCbYSR5caNG23ZkSVDhRBCCCGEEEKI3Iw8odKZTZs2WTUQBChKcvoSr4899pilc913332Wiuc9h4iUwuh60aJFFkFDZA3VADDAJupp5cqV7q677nI7d+60z/G+ODaIMMNs/IsvvrDqBUQ1wapVqyzt7uuvv3YXXHCBmzp1aqLvRlYgpLrKu+++a+1N2iVVYho0aBDTGE8IIYQQQgghhMht6A45nTh48KCZirdo0cLMqYl6QoDCub5nz57u7bffNjNyfJ4AAQqRgkipu+++282bNy8sMOExhEk5ZW1JA8Mn6ttvvw2/H4zOESmH49atWzfzcjrrrLPcOeecY+U1vYcTAhRlcRH+EAyJkPLf85QoUSLBMmfOnGlRUx07dnSrV68OC1A5pfKCEEIIIYQQQgiRXuguOR0gYgnxAsGJvz6qxptdk+pF1E27du3cunXrzIAcfErdySefnGB5pNzhJ+TFJyrnBcUQX7VNpA5Kgl5yySWWKtmnTx+XN29eE4+IeEKMIr2uU6dO7oQTTrDSpfhzRR5v32ZPPfWUK168uCtatKiJT126dLHXvYG80iWFEEIIIYQQQoiEKB0vHcCgukCBAhZZg3jEXzygEDquvvpqq5rGc7yCSP+qVKmSu+2221yePHkSLGfWrFnugQceMK8ovIkuvfTSsPhEVI2EjfQFURCR8IorrnCLFy+2Y9y5c2erVIgf17Rp01yNGjVckSJFLLKJ4090FEIV/lyk4lWsWNGWpdQ7IYQQQgghhBAieSRCpSOIRfv37zcPJ1LpEJ1IwSPVa8aMGZbKtWXLFouYwnPIs2fPHkvjQwgZPny4a9OmTYKoGokb6QveTVQfvOWWW1zr1q3dTTfdZOmUpOEhSAHtNH36dHfZZZeZ4FSoUKGwOTkCFWl94E3iJRAKIYQQQgghhBDJIxEqnfCRMJhaIyiRRkda12+//eZOOeWUcErXwIEDLfWLKCcEDvyjMDPHmPzf//53eHneuFxkDBxfUidfffVVi1zzkDqJNxRm44hTRLnRtoiIkfjoKCGEEEIIIYQQQsRGITbphI9WWrBggatbt64JUIgUpOEhJo0bN85Ej61bt5qPEBE18+fPt++ULVs2LEDhWwQSoFIPFQU//fTTmObtVCTs16+fRaaVK1cu/DptVKtWLbdr1y4ziqfKYY8ePVyZMmWiLk8ClBBCCCGEEEIIkXISmhKJROzbt8+ilzC0vvnmm5P1/iGFi5Q6hAsvUmBIPmDAABMxMLPGIwqIsKlQoUKiZUT6RInYEEVGG+3cudOOM8c2ORGPioSkS7Zq1cqON6ITFQoRpxAHvRcXgtbgwYPNv0uioBBCCCGEEEIIcWxI8YgBkUmIFlRUu+GGG8xLKKk0rFKlSpmfE75CfAZPoZdeeskMsPEeAvyh+vbt63799VdXrFixLNijnMNPP/3kHnvsMfPdeuSRR1y1atUsvRHzcFIio+Hbjmg1quPBd999Z2bxmMLDtm3bLApqw4YNJig2b948U/dLCCGEEEIIIYTIiSgdLwojRowwbyAgna5KlSpmRj1+/Phk07B4vUmTJiZU8T8ROYgYXoDCawifobPOOstNnjzZ/orUg5BEOl2zZs2sbebOnet27Nhhz4mIQoAiqinyO8G28wIU4OOFWPjll1+aqNW4cWN39tlnW4SVBCghhBBCCCGEECJ9kAgVYMqUKebbhBiBp5OPqMFInGp2vH7gwAG3ZMkSt2rVqmSXxedI3UMUGT16tLvqqqss4oboKKJsEEPkCZ96du/e7Tp06GCpdx988IGrWLGia9mypVu7dq174403LBqqffv2bunSpfZ5byienH8Tle7w5Jo5c6Ytn78PP/xwpu2TEEIIIYQQQgiRG1B1vP+xd+9e9/rrr7saNWq4kiVLuieeeMKiazp16mTC1Jo1a9zw4cPdm2++6S688EI3atSoBKbW0SD1jjS+zZs3u6pVq9qyITlfKZE8RKj98ccfJir16tXLnt97771m9j5mzBjz8CIi6tChQ+7pp5824W/atGlmLh6NYFuoXYQQQgghhBBCiIxDIlQAxI2xY8e6OXPmWFodUVD4DREFhUBBVM3QoUMtdev8889Pk2iRlJ+USF079e7d2/38889WEW/ChAlmAE+qI2LTK6+8YpFQRET5VEghhBBCCCGEEEJkLQr7+B/jxo1zNWvWtP/xG8KMvGnTppaqxXMMyi+//HJXq1Yti5hKrQAV6UkkYkNkk0+nC4Kf0zXXXOOWL19ubUQ7YCq+ceNGi1wrUKCAe++998ICFBXzhBBCCCGEEEIIkbXkOhGKNC3StSZOnBgWh/bv3++OP/54S7UjmoYoG1Lx8IR65pln7LO///67K168uFW+47158+alar0Sn1yqBTv8mQYMGGACYBBEp4suush8m/DcKlSokOvSpYuJUkRBPfjggy5Pnjzm5YUARdsKIYQQQgghhBAia8l1IhSV64h4evbZZ8PiUMGCBc3cunz58mZKXbp0afef//zHFS5c2ESrhg0bunz58tnniYaqW7eufQeUzZi+IBp5wQ6vJwziR44cmehz+HYhRA0aNMi8uu6++273/PPP2+ssA68oKhoiQG3dutXSKoUQQgghhBBCCJF15GgRKimBiJSt008/3Q0ZMsSeEzETTPXCUPy5555zffv2dX369HHXXXediVdE5Jx66qmuVatW7rLLLnMvvPCCW7FiRabtT07Gp8whGhGZ9tFHH9nzxx57zDy44ODBg+7rr7+2/0mJvPHGGy0yDeNxb/qOaMgyEK+oUEg6Je2Hf5QQQgghhBBCCCGyjhwtQvmIml27diUQpYiQwUMIU+tffvnFnnsaNWpkwsXJJ59swhMpeUQ+ASleQGU8IqI+++wzV6FChSzYs5wD3lrgU+ZeffVVd/XVV1u6I+2FBxfG8IhMpUqVcrNmzbLvIAJ++eWXrmPHjlYBD9EQaDMgLY/v0LYIV3xeCCGEEEIIIYQQWUeOr443f/58S9dCTIqke/fuZkBOKt5TTz3lpk6dGn7vhx9+cMuWLXOVKlUy8QMWLVrk+vfvb8IGEVKkg4n0ayf8nUiBJPqJ6oOen376yVWtWtUM4olCi+S3335zp512mqXcEfF0//33W8Ta448/bgKWEEIIIYQQQgghsp4cL0LBGWec4YYNG+ZatGhhz9lloqQQmq666ipL4RoxYoQZlvuqd6Ry3Xzzza558+buyiuvdIMHD3br1683n6ImTZqElwMyHU87mI/fc8897vPPP3dDhw519erVs9dpB46vj5DChHzDhg0mJgYrE5IiSYTaE088YYbyVapUcffdd59FtAkhhBBCCCGEECL7kGPS8aJpab6qGibjd955p/kMeQEKD6ISJUrYe4hMCFCAuIHIgRE5qV4vvviiGZNjWv7JJ58kEKBYjgSoYwP/rZ07d1pkmRegaDfaAQGKttiyZYuJUGvWrHHTp08PC1DgRSqipxASiVaTACWEEEIIIYQQQmQ/4j4SCmNwqtkRDZM/f/4EUTIeomzatGnjKlas6MqUKWNpXd47CLPrOnXquC5durjWrVubOOWFDXjrrbfMl4hoKoi2fHFsEAG1Y8cOS4skxRERijZA4EOgIq2uQ4cObu3atVYBD6GJNEqP2kQIIYQQQgghhMj+xO2dO8JS7dq13UMPPeRuv/12q5QG0cQIopoKFixoKXWrV6+2imqdO3e2yBmq4fXo0cPEDUD8QJfz2hzCCAKUN9CW2JH+kPL4+++/m4E4lfEQFBGgFixY4Bo3bmzVC88880zXtm1bV6BAAfOOCqI2EUIIIYQQQgghsj9xd/f+66+/WtQSFeyIbqJa2sSJE92ePXvC5uNeMPKQdke1u6JFi7oZM2a4sWPHmmG1F5pIsTvrrLNcr169EqTaBZHQkXEUL17cvJy++eYbi3zCaBz/rjvuuMN16tTJjR492pUsWdI+i+/Te++9ZxFsQgghhBBCCCGEiB/yuDhi7ty57tFHH3V169Z1S5YssYgZBCeiZxApiGqKJhh9+eWXbteuXeH3K1eubA8Py8EbCnNrxKxChQpl8p6Jpk2bWjshLm7cuNHdcMMN7s0337S2AdoZYbBGjRpu8eLFWb25QgghhBBCCCGEyMkiFMbiXbt2de3atQu/huBEBNRll10WTsl75513rJIdwpJP3bv++usTLS8Y8VS1alU3YMCAsFeUyFw47jfddJO1CRFp11xzjb3uPboUiSaEEEIIIYQQQsQ32V6E8kIR0TGIS0uXLnUHDhxwJ5xwglu+fLmlZ51++unm6bRu3Tp37733ut27d4d9g37++We3YcOGcPW7IJEpd5dcckmm7ZdIzLXXXmtpeSeeeGL4taBJvBBCCCGEEEIIIeKXbFkd78iRIyY43XzzzQmilapXr27eTlTBw99p5cqV7p577rHUrT59+pgQ1b17d6t+F4Sqaueee24W7Y0QQgghhBBCCCGEyJaRUNu3bzfz8GrVqpnYdPToUfMGmj59uqXWIUIhRl188cVmSl6pUiUTmaiWRySNT+HCR4g0LglQQgghhBBCCCGEEFlLthSh/vjjDxOOChQoYM+9OXXhwoVd/fr17f8FCxaYDxSpeFOmTHHnnXeee+WVVyyCCuEK43H5CAkhhBBCCCGEEEJkD7KlSnPBBRe4L774wi1btsyeE9EEiEoYjmNgjen4jh07zHAcAQrwfTp8+LBVztu7d2+W7oMQQgghhBBCCCGEyMYiFKl00KpVK/fuu+/a/z6iadu2be7RRx+1KKevvvrKvf/+++7pp592O3futPeLFCniGjRo4ObPn2+m5UIIIYQQQgghhBAiF6fj4feESHTKKae4888/3zVu3NiddNJJCaqhkVJ38OBBE6UQoTAnL1asmHvttdfCn+W7tWrVcvfff7+9Di1atLAIKQQp7wklhBBCCCGEEEIIIbKWTFVoFi5c6GrUqOHGjx9vaXSYi7/11lvuo48+SvRZ3ps3b56JUr46Ht5QCFCISz5Fr3fv3mZYvnjx4vB3O3fubAKVBCghhBBCCCGEEEKI7EGmqDT79+93Xbt2dXfffbfr1KmTiUuIUD179jQT8tWrV4c/GwqF7G/NmjXtf1LuEm30P/4RFpjKli3rHnnkEXfo0KHw+yeeeKIEKCGEEEIIIYQQQojclo43e/Zsq2wX6dO0efNmV65cOdeyZcvwa1u2bHFlypSxNLx69eqZgBWL++67L0O2WwghhBBCCCGEEEKkDxkeLoSv04QJE8IV7Dx4ODVt2tRdddVV5vU0YsQId9ZZZ7k333zT3icNb8+ePW779u0JDMuTwkdQCSGEEEIIIYQQQohcGAlFuh0+Tnv37nULFiwwL6d+/fq5/PnzuylTppjfEz5Ru3btMmGqTp064e9S6a579+6WxucNy5PC+0YJIYQQQgghhBBCiBwaCUUUEp5Mw4cPd0eOHEkQtXTaaae59u3bu1WrVrmpU6eaEXmvXr3ctGnT3EsvvWTeT82aNbP3EaBYljcdx1y8evXq7quvvkqPzRRCCCGEEEIIIYQQ8RgJhWBEBJKPQqJSXYkSJdwNN9wQTsXLmzevq1Wrlvk7eUi969Chg2vYsKFbv369GYkDQtY///nP8PL4PpFUBQoUOJbNFEIIIYQQQgghhBDxGAnlo5WCYhHi0RNPPOGee+4584C6+uqrw1Xv8uT5r9ZFFFT58uXd5MmTreodkVAIUIcPH3ZHjx61ZcDGjRvdn3/+aVFUv//+u1u8eHH67bEQQgghhBBCCCGEyHSOC6XS0Rvx6R//+K92tXLlShOS7rjjDle5cuWwj9PatWvdyy+/HI5+QqQi1e7HH390o0aNshQ8QHxCyPKRUKTkESGFifmQIUNckSJFLL3vhBNOSO/9FkIIIYQQQgghhBDZMRLKa1UIUKTIde3a1TVq1MhS67777rvw5x5++GETja699trw90jJI1Vv06ZN5vPUs2dPMyrHsBwBiuXdeeedlsZHxbyxY8eaAAUSoIQQQgghhBBCCCFykQjlU+9It7v00kstQglRafz48W7RokXhz1WrVs0imQYNGpTge7Vr17a/mzdvdjt27HDz5s2z53yOzxNhRWTVAw88YK97c3IhhBBCCCGEEEIIkcs8oahoN2fOHDdp0iQ3cuRIew1vJ3yevLG4/9yyZcvCnlBBKlWqZOl4/fv3d6VLl3azZs1yM2bMsOUVLFgwLD75lD8hhBBCCCGEEEIIkcuq45EqxyPI9u3bw9XwMBYnOurJJ59027Zti1rVLl++fK5KlSomUhE11bJlS3vdG51LfBJCCCGEEEIIIYTIeaTamBz++usvd/zxx7tnnnnG0vO2bt1q6XmITx988IHr3r27u/XWW+05AtVFF11k32NVPj0vSFKvCyGEEEIIIYQQQoicQZrCjhCgVqxYYV5QL774oqXoYUSOifiCBQtc4cKFXfXq1c376cILL3Tr1q2z70UKTV7/kgAlhBBCCCGEEEIIkbNJUyTUjz/+6CpXruyuuOIKS8EjJY8IKFLwevXq5fLkyeMGDhxo0VEdO3Z0l112mevTp4+l4gkhhBBCCCGEEEKI3EeaRCiYPXu2a9CggXv77bfd0KFDzedpyZIlrnfv3u7KK690jzzyiFXAu/vuu02IEkIIIYQQQgghhBC5lzS7gCNAQf369S3yaf369e6jjz5ya9eudZdffrnLmzev++abb8ICVBq1LiGEEEIIIYQQQgiRmyOhgnz44YeuTZs27owzznBnn322GzJkiCtZsmS46p0q3gkhhBBCCCGEEELkbtJFhKJaXr9+/Swlr06dOvaaxCchhBBCCCGEEEIIka4iVBBVvBNCCCGEEEIIIYQQkeRx6SxASXwSQgghhBBCCCGEEJGka76cBCghhBBCCCGEEEIIEQ2ZNgkhhBBCCCGEEEKIDEcilBBCCCGEEEIIIYTIcCRCCSGEEEIIIYQQQogMRyKUEEIIIYQQQgghhMhwJELlYA4ePGgVCzODaOv566+/Yn4vJZ9JCX///XfUbUhu//fu3Wvfy8kcPXo03Y6xEEIIIYQQQghxLEiEiiOqVq3qPv/880SvlypVym3evDnR682bN3eXX365u/baa129evXc9ddf7+rUqeNq1qzprr76alexYkU3YsSIY96u7du3uzPOOCPR6//3f//nzj77bHfRRRe5iy++2BUvXtwVLlzY1str5557rmvVqlWq1lWlShW3dOnSqMdm7ty5iV5n37/66quoy2rRooX74IMPYq7zvvvuc5deeqm76qqr3BVXXGGPypUrux49eoQ/061bt6jHEhEoKX7//Xd34MABlx7Mnj3bNWjQINHrixcvdjfccEPU78yfP9/Vr18/XdYvhBBCCCGEEELEIk/MT4hsw6ZNm9xxxx2X6PU8efK4AgUKJHr93Xfftb/Tpk1z11xzjTvttNPsOUIWolHp0qVjrnP48OFu6NCh7vjjj7eoIv9AXNmwYYN95sQTT7RHJM8//3yC5wgefGf58uW2vNRCRM+aNWvcv/71r0Tvsby8efMmev2kk05yt956qytYsKBt4z/+8Q/3559/2vZzPP/5z3/GXO/TTz8dPu6IUaNHjzYhLRhFxfvR1n/77be7888/3z344IOJ3nvqqafcb7/95l5++eWY2/D999+7e+65x/a/XLly7plnnnHnnHNO+H32K1rUF9v12WefWfvzGR5sN/u/e/duEwKFEEIIIYQQQojMQJFQccKKFStMsJg+fXqi97xAlBQvvfSS+/rrr8PP+/Xr51auXJmi9Xbq1MmtXbvWrV692gSQb7/91n344YcJRCREsFii0pNPPmmRP4g43bt3TzZCKClYLyl0RPcEU/B4ILZE2wZEl/Hjx9v+E0HFd7/88kt7Xr169aiiXiT+M/v37w8fB5bLfnvYhhNOOCHRd/lMUkIXAhmPlNCsWTMT01g/0WNEN0WmEkbbF7aL6LGFCxe6jz76yKKf+Lto0SL34osvpmj/hRBCCCGEEEKI9EAiVJzQt29fiyyaMmWK+/HHHxO8hyASzffn8OHD9rdu3boJRCf+J00NYnlGsexIPvnkE0t/8yD+BAUZD8tG9GnYsKGJHu+9954bNWqU+/nnn90ll1ziXnvtNbdz584U7T/L6tOnj4kvgwYNstdmzZplaXEsi5S7aPty5MiRqPvAawgwqRHDiD4icmjAgAH2PQQhIqJIz5s8eXJUEQxh6vHHH3clS5a0yLOyZcu68uXLW5piZKRYUixZssQiuUgfZB2tW7d2p556qolJtWrVcuedd5678847kxShkkN+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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vnmb9/Pd7343Dj300Pj4xz9e/LzZZpsVgVQGVUcccUTU1dWtk/4DAAAA0AlHSjUOpCoWLVoU/fv3X6P9XHfddXHIIYc0adt2222LqXz33Xff2+4nAAAAAF10ofOcknfuuefG5MmTi3WmKubPn19My8tpfOutt17stttucdddd1WvnzVrVrzyyistjqwaM2ZMPP7446XVAAAAAEAnmL6Xtthii3jppZdiwYIF0adPnzj77LOLf9PQoUOLsClHPZ1xxhnRs2fPuOaaa2LvvfeOP//5z7H11lsXoVWvXr2KBdGbGzZsWMybN6/V+16yZElxqcj1qNLy5cuLS6qtrS0uub5VXioq7StWrIiGhobVtucUwpqamup+G7en3L4t7T169Cj227g995vbN+/jSu0NldvURNTURjTktm/28c32pvfZentt3knL7YX6trXX1EUUj1VL7c372Fp716+p+WuyU732mvWxSxxPalKTmtSkJjWpSU1qUpOa1KSmaKnvzW/bYUOpJ598strhHNV0/PHHF2fSu+iii2KbbbYp1phq7MgjjyxGU/3sZz+L888/v5gCuHTp0mLaX9++fZtsm4ui5xS+1px11llF2NXcgw8+WJ1CmKOzcsTVc889F6+99lp1mw033LC45KLsc+bMqbbniK6RI0cWNWSfKsaOHVucOTD33fjJGTduXBGqTZo0qUkftttuu6Kuhx56qNqWT/T2229f3N8TTzxRbc+687HK0Wa5aHzF4MGDY8stt4zp06fH1KlTo9/sN+53ee9hsbT/RtFr4dToseT16vbL+m5QXHrPfz7qlr0Z5i3tPzqW9x4efeY+HbUrFlfbFw/cNOp7Doq+sx+NmiI4ecOiwWOjobZn9Jv1cJOaFg7dOmrql0XfOW/2vaGmNhYNHRe1y+dFn3lv9r2+rk8sHjw2eiydFb0WTKm2r+g5MJYMHBM9F78aPRe9XG3vDjVNmlTXaV97FV3peFKTmtSkJjWpSU1qUpOa1KQmNfVtsaa2ru1d09A4PusAHnvssdh5552LQKk1//mf/xl//OMf4+qrr64+Ubfffnsxcqqxd7/73XHppZfGLrvs0uaRUqNHjy7OBDho0KBOn0w2b79i8sJuM6qoK9Z06Af6ddrXXvM+doXjSU1qUpOa1KQmNalJTWpSk5rU1HLfc9Zazl7LEKuSr3SKUOr3v/99HH300fHCCy+0us0BBxwQO+ywQ5xyyinFz5/+9KeLlPDMM8+sbpOJ3kc+8pEiZcwHri0ylMqEcnUPWmd12f0L2rsLvA1H7LBmJwAAAACA9tDWfKVdFzrff//94/rrr4/FixcXid0dd9wRxxxzTJx++unF9Tka6rDDDov/+7//K9K4HA72la98JR599NE47rjjqvvJcCqn8/32t7+tTgk84ogjivWp2hpIAQAAAFCedg2l8qx6P//5z4tRTjnvMcOlCy64ID772c8W17///e8vpuR95jOfKdaGyjmWOa3vnnvuKeZDVmy22WZx4403FmtE5Xa5EHqGVrn+FAAAAAAdT4ebvteeTN+jIzN9DwAAgM6gU0zfAwAAAKB7EkoBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAA0L1CqbvvvjsOPvjgWH/99WPQoEGx0047xcSJE5tsU19fH9/5znfine98ZwwePDj222+/ePHFF1fa1yOPPBK77757DBw4MDbZZJO44IILSqwEAAAAgE4TSk2YMCH22WefePbZZ2PmzJlx0kknxUEHHRRPPfVUdZtTTz01HnjggXjwwQdjxowZsddee8VHPvKRWLx4cXWbadOmxfjx44v9zZ07N37/+9/HxRdfHJdcckk7VQYAAADAqtQ0NDQ0RDuZP39+DBgwoEnbF77whXjve98bxx9/fBE2bbnllsXIqCFDhlS3OeCAA4pg6rjjjit+PvbYY4tRVP/2b/9W3SZDrAyqpk6dGnV1dW3qTwZauZ85c+YUI7e6msvuX9DeXeBtOGKH/u3dBQAAAFhr+Uq7jpRqHkilRYsWRf/+b3z4vummm2LPPfdsEkilnPJ3ww03VH++7rrr4pBDDmmyzbbbbltM5bvvvvvWWf8BAAAA6OQLnefUvHPPPTcmT55chE7p8ccfj80333ylbceMGVNcl2bNmhWvvPLKarcDAAAAoOPo0d4d2GKLLeKll16KBQsWRJ8+feLss88u/q1M79tggw1Wus2wYcNi3rx51W169eoV/fr1W+V2LVmyZElxaTy8LC1fvry4pNra2uKSC67npaLSvmLFimg8A7K19pxCWFNTU91v4/aU27elvUePHsV+G7fnfnP75n1cqb2hcpuaiJraiIbctvHszUp70/tsvb0276Tl9kJ929pr6iKKx6ql9uZ9bK2969fU/DXZqV57zfrYJY4nNalJTWpSk5rUpCY1qUlNalJTtNT35rftsKHUk08+We1wjmrKtaTyTHoXXXRRMb1v9uzZK90m23JqXsptli5dWkz769u3b6vbteSss86KM844Y6X2XI+qMoVwvfXWK0ZcPffcc/Haa69Vt9lwww2LSy7KnnMkKzbddNMYOXJkUUP2qWLs2LHFNMTcd+MnZ9y4cUWoNmnSpCZ92G677Yq6HnrooWpbPtHbb799cX9PPPFEtT3r3mabbYrRZrlofEXO38w1uaZPn16srdVv9hv3u7z3sFjaf6PotXBq9FjyenX7ZX03KC695z8fdcveDPOW9h8dy3sPjz5zn47aFW8uML944KZR33NQ9J39aNQUwckbFg0eGw21PaPfrIeb1LRw6NZRU78s+s55s+8NNbWxaOi4qF0+L/rMe7Pv9XV9YvHgsdFj6azotWBKtX1Fz4GxZOCY6Ln41ei56OVqe3eoadKkuk772qvoSseTmtSkJjWpSU1qUpOa1KQmNampb4s1tXVt73Zd6Lwljz32WOy8885FoPTjH/84br/99rj22mubbPOrX/0qLr300uIse5UnKrfbeuutm2z37ne/u9hul112afNIqdGjRxdnAqwsxNWZk8nm7VdMXthtRhV1xZoO/UC/Tvvaa97HrnA8qUlNalKTmtSkJjWpSU1qUpOa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l/jEJz4RG220UfTt2zfe+c53xsc+9rGYOHHiuushAAAAAN03lLr99tvj4x//eOy7775xzz33xNy5c+Ovf/1rfPazn40JEybE//7v/67bngIAAADQvdaUSuecc05cfvnl8Y//+I/VthEjRsQBBxwQ733ve4vF0MePH7+u+gkAAABAdxwp9eqrr8a4ceNavG7QoEExc+bMtdkvAAAAALqwNodSu+22W5x33nkrtdfX18epp54au+6669ruGwAAAADdffret7/97TjssMOK0VI5hW/o0KHF6Kmbb7453ve+98W55567bnsKAAAAQPcLpfr37x/XX399PPTQQ3HvvffGa6+9Fttvv318+ctfjve85z3rtpcAAAAAdM9QqiJHSrW2thQAAAAArNU1pQAAAABgbRFKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAANC9Q6mRI0fGjBkzqj+/8MIL0bdv3xgyZMhKl+nTpze57ZQpU+KAAw6IwYMHx6hRo+KMM86I+vr6dqgCAAAAgE4RSi1YsCDOO++8eO2115q0NzQ0RF1dXcyePXulSwZPjW+/1157xfjx42PmzJkxefLkuOuuu4pgCgAAAICOp91DqQsvvDDWW2+9+PrXv/6W9/GjH/0ott122/j85z8fPXr0iHe84x3xq1/9Ks4999wipAIAAACgY2n3UOrYY4+NhQsXxuLFi9/yPq677ro45JBDVpoKuOOOO8Ytt9yyFnoJAAAAwNrUIzq4XBfqtNNOi6uvvrqY3rfZZpvFN7/5zWL9qIrHH388Nt9885VuO2bMmOK61ixZsqS4VMydO7f4d/ny5cUl1dbWFpfsR+M1qirtK1asKKYZrq49pyHW1NRU99u4PeX2bWnPkWC538btud/cvnkfV2pvqNymJqKmNqIht32zj2+2N73P1ttr805abi/Ut629pi7narbS3ryPrbV3/ZqavyY71WuvWR+7xPGkJjWpSU1qUpOa1KQmNalJTWqKlvre/LadMpTKRc532WWXGDZsWPzpT3+KQYMGFSOfjjrqqLjiiiti7733LrabP39+DB06dKXb5+3mzZvX6v7POuus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yPltt91WjJbK0U7bb7997LHHHnH66ae3d9cAAAAA6KrT99K73/3u+N3vftfe3aAd5DTMb33rWytNxwTWHccdtA/HHpTPcQftw7HX9dU0rO78fAAAAACwlnWZ6XsAAAAAdB5CKQAAgBb88Ic/jFmzZrV3NwC6LKEUAOvM8uXLY/HixTF//vxYsWJFe3cHAFZpyZIlTX4+++yzi79ja+Jd73pXPPvss2u5Z9A51dfXt9q+bNmy0vtDxyOUokN76qmn4jOf+Uzstttucdhhh8Vdd93V5Pobb7wxDjrooJV+wV188cXxkY98pDgL43bbbRfvf//7Y+utt47DDz88/vKXv5RcBXQu+Qbh+OOPj0022STGjh0bP//5z4v2//u//yuOpbT77rvH7bffXr3NrrvuGuPGjasec9tuu21x2XnnnWOvvfaKd77znfHggw+2W03QWeRxt6YfZs8888z49re/3aRt3333LU4A8973vrf4+5fH5/ve977i/8cdd1yxzcknnxzf+MY31mr/oTPZf//9409/+lOTtjx795///Ofqz3369ImampoWb//d7363OPt3c/kljEWZIeKPf/xjDBo0qHhPmO8Pd9ppp9hll11ihx12KN4z5vvJNZHLYQ8cOLD4t7F8f/rBD36weD/6j//4j8V95H01/kyZ70fpmLrU2ffoWl588cXiF9WFF14YH/rQh+Luu++O/fbbL377298Wv2hSr169om/fvk1u973vfa/4BXjppZfGqFGjmozYuPXWW+NjH/tYTJo0KTbYYIPSa4LO4N/+7d+irq4u/va3vxUjnD784Q8XbxyybejQocU2PXr0KN5kVOQxtyr5YXjYsGHrvO/QkeWb5rlz5xbHT+VLlDzGMvAdOXJk9QNwbe2b3xledNFF8R//8R9Fex6D+bcs9/Hcc88VP6f8wFzZZ8X//M//FG/ac19f/vKXi3/POeec4rrcR+rZs2dxge4qj4uZM2fGjBkziuMxw6S8NH5v2fzYaiz/9uUH7eby2Mz3qNDd5d+YfA95xx13tPk2f/3rX+Oss86KqVOnFl+snHLKKbHRRhtV/95VLo3df//9TY7VV155pfjMV5HHo/O7dVxCKTqs3/zmN3HMMcfEAQccUPz80Y9+NL74xS/GZZddVg2lUuVNeUWGV5/73OeaBFIpf1GNHz+++Lb40UcfFUpBK66/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Diu1/7//9/9i7Nix8b73va+4jBw5srhsvfXWsc0228QWW2wRJ5100hrd1zvf+c546aWXWmx/4oknVmrfZJNN4rXXXmtxXzvuuGM89dRTbbrfv/71rzF37txY27bddtu48847Y12ZN29enHbaacXzM27cuOJx33LLLYvn4Mtf/nK8+uqrLd5u6dKlxXOWt8vbPProo02uP+KII+JnP/vZOus3ABDRo707AAB0HfPnz49vf/vbRQix3nrrxYknnhgf+tCHqtf37t07amtr2zyKpaampnq7urq6Jtd/8YtfjGuuuabY3/Lly4tLbp8jkw455JC4+OKLo1evXqsdqZSBxtVXXx09evQoRiNVLqNGjYqJEycW2+R+8tLctddeW/1/3n8GMCNGjIg77rgj3ooMl2bMmBHveMc7Vrou6+/bt+9K7dmv3XffPfr06RM9e/YsHo8MXJYtWxYvvPBC0d4W//Iv/xLf+MY34sMf/vAa9fkPf/hD/Md//EfR7z322CNOP/30GDBgQJP+NX/uMiz67//+76Ke7G8+R5WRYPm858/5eGYotPfee6/y/g8++OAiGLzpppti/fXXr7bPnj07fvKTn8RHP/rRYqRdxaJFi4rnJ19T559/fnG/eX8vvvhiPPvss7HXXnsV/crr2/rYAQBvjVAKAFhrDjvssGL0ya233hoPP/xw/PM//3MRPmy33XbVgKL5NLQMDr761a8WQUwGQxmoZMBx3HHHxb/+678W22TY0twFF1xQXNIVV1wRt912W/zXf/1Xk23y/jKEWJUzzjgjzjzzzJVGRn3nO9+p/pz9ah6sNJahxpe+9KV473vfG1OnTi36naO0KqHamowky/ofeOCB2H777YvHKkObyr8t9SHbM2TJEVqN5W1y5FBb+5AhTEuP86rcf//9xfN05ZVXxoYbblgEkocffnhRR0VLz/m5554b5513XvXnyy67LE4++eSYNm1a8VhmoJaPQ//+/Vfbh3vuuSd++ctfxvDhw5u0DxkypBgll4HZnDlzYvDgwUX74sWL46677iqCp3w88/Gr3N+SJUuK0WUZRuXjtqrnHAB4+0zfAwDWipz+9be//a0IeYYOHRq77rprfOtb34qzzjqruk2GHs3X8cm2gw46qJhm9thjj8UzzzxThFQZBFWsLhzIEUEZQjTXeB+taWnk1p/+9KfYZZddmtx/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nutrition_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\", \"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\", \"์„ฑ๋ถ„ ์ •๋ณด ์–‘์‹\", \"์„ฑ๋ถ„ ์„ ๋ช…\", \"์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ\"]].copy()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\")][\"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=30, ha=\"right\")\n", + "plt.xlabel(\"์ƒํ’ˆ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์„ฑ๋ถ„ ์ •๋ณด ์–‘์‹\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์„ฑ๋ถ„ ์„ ๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์„ ๋ช… ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"]==\"O\")][\"์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์˜์–‘ ์ •๋ณด (์ „์ฒด ์ƒํ’ˆ)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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SAX0VQCSdva9tWvXWv369W316tV2zz33uLaGDRvakSNHinL7ACBgzJgxgaxNDSXW3bv27du7wpsAkErozwCkAvoqAEkZlFLg6Qc/+IErcrd3716rXbt24DEi5gCKC1mYAEoK+jMAqYC+CkBxK3QE6auvvrLOnTvbT37yE1dPStFyRc093pShAAAAAAAAQDQxRZBWrFjhUjT/3//7fzZjxgx7/PHHrXfv3u4xZUlpXLGG8ik4pfHFAAAAAAAAwDkHpX7+85/b5s2b3cx6zz//fCAgJVdccYXNnj3b7r33Xvv73/9u7dq1i+UlASBm3/3udy09Pd0FvVVgU4v3/0htmglUs4YCQLKhPwOQCuirACRVUGrJkiXu33//+98uS+qvf/2rvf7661avXj27++67rUOHDjZ37lxbtWqV/eMf/yjubQZQyvzv//6vlStXzsqWLeuKbSpz01sinRhdfPHFid5kAIiI/gxAKqCvAhAvhSoA1bp1a3vjjTdswoQJ9u1vf9sWLlxojRs3tk8++cT+9a9/2eWXX+5+BoCidMsttyR6EwCgSNCfAUgF9FUA4uWspsq755577De/+U1gGF+1atXspptuOueAVJ06dVx9qnDjx4+3Jk2aWGZmpl133XW2Zs2afOts27bNevXqZVWrVnX1rR555BHqWwEAAAAAAJSkoJTcdddd9oc//KFINuLo0aP27LPP2u7du/M99vLLL9vEiRPt3XfftYMHD9qgQYOsW7dutmvXrpDna0bA7t272969e23lypVuyKECUwBKjo8//thuv/12a9SokVWoUMHOP/98u/nmm23RokWJ3jQAKBT6MwCpgL4KQNIGpaR9+/bnvAEvvviim8FvxIgR+R47fvy4a580aZLLwkpLS7O+ffu6DK0xY8YE1hs3bpy1adPGBg4caBkZGa7W1ZQpU2zs2LEuSAUg9Skwfeutt1qPHj3sgw8+sEOHDrk6dz/5yU9s6NChbqIFAEgF9GcAUgF9FYCkD0oVBc3ad+zYMReACqcIvKLyLVq0CGnv06ePm/HPM2vWLBesCh8KqKDZggULinHrAcTLM888Y5MnT7Yf/ehH1qBBA1d0s1atWm7Y7syZM+2FF15I9CYCQEzozwCkAvoqAKUiKFWQdevWWfPmzfO1N23a1DZt2mQnT54843p6DEDq+/rrr61Vq1YRH6tSpQpZ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40P//v3tqaeeskqVKiV6cwAAAAAApQyZUkAppeyo5s2bW48ePRK9KQAAAACAUoigFFAKffLJJzZ58mQbM2ZMojcFAACgyLPBZ8yYYV27drW6deta7dq1rVevXvbZZ58letMAAGEISgGlTFZWlg0YMMAmTpxoFSpUSPTmAAAAFKmDBw/a888/b8OHD7etW7faF198YR06dLDOnTvb4cOHE715AIAg1JQCSpkVK1bYhg0brFOnToG2nJwcF6yqVq2aO2HT3UUAAIBUVLVqVVu8eLH5fL5A24gRI1yW+PLly+2GG25I6PYBAE4jKAWUMtdee60dO3YspG3RokV233332dq1axO2XQAAAEUhOBjlOXnypO3bt8+qVKmSkG0CAETG8D0AAAAAJbrG1NChQ61ly5bWtm3bRG8OACAImVIAAAAASqT9+/db//79XS2pWbNmJXpzAABhyJQCYNdffz1D9wAAQImybNkya9eunX3rW9+yhQsXutqZAIDkQqYUAAAAgBJlzpw5NnjwYJs2bZp17Ngx0ZsDAIiCoBQAAACAEmPv3r1277332ttvv22XXHJJojcHAFAAglJASfKXV+L3XgPujt97AQAAxOiNN96w3r17E5ACgBRATSkAAAAAJcamTZvspZdessqVK+dbHnjggURvHgCgpAaltm3bZr169bKqVata/fr17ZFHHrG8vLxEbxYABNBPAUgF9FVIZWPGjLHjx4/bkSNH8i1PPvlkojcPRYR+CigZSkxQ6ujRo9a5c2fr3r27G0e+cuVKW7JkieucACAZ0E8BSAX0VQCSHf0UUHKUmKDUuHHjrE2bNjZw4EDLyMiwevXq2ZQpU2zs2LGuowKARKOfApAK6KsAJDv6KaDkKDGFzmfNmmUjRowIaatTp461b9/eFixYYHfccUfCtg0AhH4KQCqgr0Kxm/uYlUg9RiZ6C0oN+img5CgxmVLr1q2z5s2b52tv2rSpewwAEo1+CkAqoK8CkOzop4CSo8RkSqlwYfXq1fO116hRww4fPhzxOSdOnHCL5+DBg+7fffv2WU5Ojvt/WlqaW1Q0L7hwnteem5trWUeOBr2q75tYX27Yu6V981ikdsmLqf3QoVzz+/3ufQPv6PNZenp6vm2M1h7LPuk97OipY5NmfkvzmeX6feYP2pZ085vPZ5bj136Ftkuuxdae4fOb/+DB+OyT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MTQbNWpUHFZeSHa7K+s5SJIkSZKkwgylahACnJtvvjk88sgjsQ2PKilmMFElRQhDJdGll14a29c22mijBQpmis2jqsjndM4554Qvvvgirrh31113xeHrtBESPl177bWxUoqKqdRmKEmSJEmSqj9LRWqI22+/PbRt2zb+nxlMDDffd999Y7sanzPwfIsttgjt2rWLFVXzG0jlz2la2Kh8Su13WcyD2nHHHcMbb7wRnw/bzJDyadOmxSqwevXqhUcffTQXSLEinyRJkiRJqv4MpRYxtKrRsnb33XfnwqI5c+aExRdfPLbmUUFEZRGte8yUuuSSS+J1f/jhh7D66qvHlfX42tixY+frcSsqjEphF/Odhg4dGsOzLEKoTTbZJM59Yr5VgwYNQu/evWNIRZXUaaedFurUqRPnZhFI8TpIkiRJkqTqz1BqEcPKeFRE/etf/8qFRfXr148DwNdZZ504uHuttdYK//znP0PDhg1jiLXHHnuEZZZZJl6faqkOHTrE26AquzcJkVLYxawohrNfd91181yPGVkEU8OGDYtzsfr27Rsuv/zyeDn3wawpVhckkPr4449jy6IkSZIkSareDKWqsWKBEW1rK620Urj44ovj51QJZdvdGFB+2WWXhcGDB4eBAweGnXfeOYZZVCGtsMIKoXv37qF169bh3//+d3jzzTdDZUstdoRIVHk99dRT8fMBAwbEeVeYO3dueP311+P/aTfcc889Y5UXg8zTwHUCN+6DMIvVAmlV5Lkyf0qSJEmSJFVvhlLVWKoimj17domQiqog5iox+PvLL7+Mnyd77713DGeWW265GETRwkdlFGhzAyvvUTH10ksvhXXXXbfSng9zrJBa7K6//vqwzTbbxFZCnhvzrhjKTui05pprhjFjxsTbEKC9+uqroUePHnGFPQI38PxAGx+34XUgyOL6kiRJkiSpenP1vWpu3LhxsWWNcClfnz594kBzWveGDBkS7r333tzXPvnkkzBx4sTQsmXLGPDgueeeC+eff34Mb6igoiWuqp4T86FoL6Q6ipUAk88//zxst912cTg7FV35vv7667DiiivGFj0qok455ZRY/XX22WfHQEuSJEmSJC0aDKUWASuvvHK44oorQteuXePnfMuooiJ42nrrrWMb2/Dhw+MA9LSqHu1sXbp0Cfvvv3/YaqutwkUXXRQ++OCDOLtp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XRZnSG2zzTa5VfXq1Pm/7I4qqXXWWSfcc889cVU9KqUIpH755Zfw+++/x/vAtGnTwq+//hqrrH744YcwYcKEKny2kiRJkiRJ1c9if9ayCduEUX/72/9lcW+//XYMlnr27BlatWqVmwM1ZcqUcPXVV+eqowitaM377LPPwg033BBb9kAYRbCVKqVo4aOCiqHoF198cWjUqFFsB1xiiSWq7PlKkiRJkiRVR7WmUiplbwRStNQdc8wxYe+9946teO+//37uemeccUYMkXbaaafc7Wjho7Xvww8/jHOiTj755Dj4nAHoBFLc31FHHRXb/liR7+abb46BFAykJEmSJEmSanEolVr1aM/bfPPNYwUTIdOIESPCc889l7ve9ttvHyudhg0bVuJ2u+yyS/x3+vTpYebMmWHs2LHxc67H9anAovLq1FNPjZenYeeSJEmSJEmqxaEUWDHvkUceCf/5z3/CddddFy9jNhRzotKg8nS9iRMn5mZKZbVs2TK2751//vlhrbXWCmPGjAkPPPBAvL/69evnwqjUIihJkiRJkqRavvoerXV8ZH366ae51fYYVE711HnnnRdmzJhRcNW8ZZZZJmy77bYxtKKqqlu3bvHyNDjdMEqSJEmSJKlstW7QOf7444+w+OKLh0suuSS283388cexnY8w6oknngh9+vQJBx54YPycwGqTTTaJt+OlSu18WcUulyRJkiRJUmG1sqyHQOrNN9+Ms6SuvPLK2NLHYHOGko8fPz40bNgw7LDDDnF2VPPmzcN7770Xb5cfPKU8z0BKkiRJkiRp/tTKSqnPPvsstGrVKmy55ZaxZY8WPiqkaNnr379/qFOnTrjgggti9VSPHj1C69atw8CBA2PrniRJkiRJkv66WhlK4eGHHw677757uO+++8Kll14a50S98MIL4ZxzzglbbbVVOPPMM+MKe3379o3BlCRJkiRJkhaeWtm+BwIp7LbbbrEy6oMPPghPPfVUmDJlSthiiy1C3bp1w1tvvZULpGppdidJkiRJklQham2lVNaTTz4ZDj744LDyyiuH9dZbL1x88cWhSZMmuVX1XFFPkiRJkiRp4TKU+v/V+M4999zYwte+fft4mWGUJEmSJElSxTGUyuOKepIkSZIkSRWvTiU8xiIVSBlGSZIkSZIkVTz70zIMpCRJkiRJkiqHoZQkSZIkSZIqnaGUJEmSJEmSKp2hlCRJkiRJkiqdoZQkSZIkSZIqnaFUDTF37ty4emBlKPQ4f/zxR5m3K891Ksr//M//hJru999/r9LXWJIkSZKk+WEoVU1tt9124eWXX57n8jXXXDNMnz59nsv333//sMUWW4SddtopdOzYMey6666hffv2oW3btmGbbbYJLVq0CMOHD//L2/Xpp5+GlVdeeZ7LTzzxxLDeeuuFTTbZJGy66aZh9dVXDw0bNoyPy2UbbLBB6N69+3w9VrGApXXr1uGjjz6ar/s6++yzw2mnnVbm9fr16xc233zzsPXWW4ctt9wyfrRq1Socf/zxuesce+yxBV9LQqFifvjhh/DTTz+FheHhhx8Ou++++zyXT5gwIXTq1KngbcaNGxd22223hfL4kiRJkiQtDHUWyr1oofvwww/DYostNs/lderUCfXq1Zvn8oceeij+O2rUqLDjjjuGFVdcMX5OsEWItNZaa5X5mNdcc0249NJLw+KLLx6rodIHYcvUqVPjdZZccsn4ke/yyy8v8TkBCLd544034v2V1y+//BL69+8fPvjgg7D00kuH7777LoZJhG1ZSy21VInPn3766TB06NC4bbxuK620Uhg2bFho0KBB/Pqyyy4bfv311zIf/8ILL8y97oRTN954YwzWspVWfL1u3brz3PaII44IG220UcHwa8iQIeHrr78OV199dZnb8N///jeccMIJ4Z133gnNmjULl1xySVh//fVzX//b3/5WsFqN7XrppZfi95/r8MF28/375ptvYjAoSZIkSVJ1YaVUNfTmm2/GAGP06NHzfC0FRsVcddVV4fXXX899fu6554a33367XI/bq1evMGXKlDB58uQYiLz77rvhySefLBEqEYqVFTKdd955sTKIUKdPnz6lVhAVqmiiGuz+++8Pd999d7jzzjvDSSedFF544YVYPbbDDjvEbcuGRDNmzIjVS7fddlu8Ha/b3nvvHQ499NDcdZZYYolw2WWXhZYtW8b7LSYFUnPmzMm9DoQ7PO+E15/7y8d1CNIKIUTLD9KK2W+//cKBBx4YH5/qMqqf8tsPCwWWbNe2224bnnnmmfDUU0/F6ij+fe6558KVV15Z8DaSJEmSJFUVQ6lqaPDgwbHyaOTIkeGzzz4r8TUCkkJtbVQYoUOHDiVCKP6fqozKmjnFfed79tlnYxiUEEhlA5qE+6Z9bI89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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAATYRJREFUeJzt3QmYXFWZP+Cvu7MSsrOGVWAgLLLvjCwKCmGTRUFQQRQQUEBgAoqAuMCgDCCDgqBm2AKyDALDCMguIEsifzZZhy2ALCEhCdmT7v/zXaymutOddCC5vb3v89ST7tO3bp1TVTdV9avvnFvT0NDQEAAAAABQotoybwwAAAAAklAKAAAAgNIJpQAAAAAonVAKAAAAgNIJpQAAAAAonVAKAAAAgNIJpQAAAAAonVAKAAAAgNL1KP8mO676+vp48803o3///lFTU9Pe3QEAAADodBoaGmLKlCkxbNiwqK1tvR5KKFUlA6mVVlqpvbsBAAAA0OmNGzcuVlxxxVb/LpSqkhVSlTttwIAB7d0dAAAAgE5n8uTJRdFPJWdpjVCqSmXKXgZSQikAAACAj29BSyNZ6BwAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUIoOqaGhIa677rrYeeedY7nlloull1469txzz3juueeKv0+ZMiXOOuus2HDDDaN///6xwgorxPe+972YNm1ai/u64IILYu21146BAwfGuuuuW1wXAAAAaD9CKTqkSZMmxfnnnx8jR46MV155JV577bXYaqutYscddywCqdGjR8eTTz4ZV155ZfH7o48+Gi+88EIcffTR8+zrmGOOiWuuuSauv/76Yr833XRTzJkzp13GBQAAAHyopiHLSChMnjy5qKTJ4GLAgAHt3Z1urfK0rKmpadK+3nrrFWHV5ptvHksuuWSTv7311ltFFdR7773X2Hb33XfHN7/5zSLA6tevX0m9BwAAgO5rchvzlR6l9graqHkYlWbPnh0TJkwontDNA6k0ffr0eYKnCy+8ML773e8KpAAAAKCDMX2PTlM5ldPwcl2oTTfdtMnfZs2aVUzf++pXvxqnnnpqk789+OCDxbS/c889t6iyyrWpPve5z8XYsWNLHgEAAABQTShFhzdx4sRikfNnnnmmWBeqYtSoUTFo0KCiJDCn8/Xu3Ts+85nPNLnuO++8EyeccEI8//zzccstt8S4cePiy1/+crE2Vf4MAAAAtA+hFB3aI488EptttllssskmceeddxYhVMU3vvGNeP/994tpezlPdb/99outt946XnzxxcZtevXqFSNGjCim8a2yyirRp0+fOPzww+Pzn/98sUg6AAAA0D6EUnRYN998c+y7775x6aWXxmmnnRa1ta0/XXOdqQybcmre//zP/zS2r7XWWrHqqqvOs/0666xTnNUPAAAAaB9CKTqkPIPeEUccEbfeemtss802bb7eG2+8UUznq9hnn33iV7/6VePZ/CrGjBkTa6655iLtMwAAANB2Qik6pGuvvbYIlLKiqSVXXXVVsfD5yy+/XPw+fvz44vcMs3IaX0W25dS+Qw45JN5+++1iqt/ZZ58djz32WDH9DwAAAGgfQik6pFwX6je/+U0sueSS81xOPPHE2HnnnYuKqF133TX69+9frDtVX19fnG1viSWWaNxPv3794p577il+Hj58eCy77LLxl7/8Je67774YPHhwO44QAAAAureahubzmrqxyZMnF0FHVtbkGkUAAAAALJ58RaUUAAAAAKUTSgEAAABQuh7l3yTt5bJHprZ3F/gEvr55v/buAgAAACwyKqUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDuFUo1NDTEddddFzvvvHMst9xysfTSS8eee+4Zzz33XJPtLrroolhttdWif//+se2228aTTz45z77GjRtXXHfgwIExbNiwOP3006O+vr7E0QAAAADQKUKpSZMmxfnnnx8jR46MV155JV577bXYaqutYscdd4wpU6YU21x88cUxatSouOuuu4rtjzzyyNhll13i7bffbtzP1KlTi+uMGDEi3nvvvRg7dmzcf//9RTAFAAAAQMdT05DlSu2kctM1NTVN2tdbb70irNp6662LqqcHH3wwhg8f3vj3Y445Jnr16hW/+MUvit/POuuseOyxx+Lqq69u3Oadd96JNdZYI15++eUYOnRom/ozefLkotIqw68BAwZEV3PZI1Pbuwt8Al/fvF97dwEAAAAWWb7SrpVSGUY1D6Rmz54dEyZMKDp9zz33xMorr9wkkEr77bdf3HjjjY2/33DDDbH//vs32WaZZZaJLbfcMm677bbFPAoAAAAAOvVC51k5lVVQa6+9dmy66abxzDPPxJprrjnPdquvvnq8+OKLRYCV5rdd/g0AAACAjqVHdBATJ06Mgw46qFhLKiuf0gcffBCDBw+eZ9shQ4YUAVauJTVo0KD5bldZm6olM2fOLC7V5WVpzpw5xSXV1tYWl1w0vXrh9Er73LlzG6chzq+9rq6uqAqr7Le6PeX2bWnv0aNHsd/q9txvbt+8j/O0N1SuUxNRUxvRkNtWz96stDe9zdbba/NGWm4v1LetvaYuE8lW2pv3sbX2rj+m5s/JTvXca9bHLnE8GZMxGZMxGZMxGZMxGZMxGZMxGVO01Pfm1+3QodQjjzwSBxxwQHzta1+LU045pbgT05JLLhnvv//+PNtnWw68X79+TbZbfvnl59kug6nWnHnmmS0uhp7rU1X2nWcEzIqrXJvq3XffbdxmxRVXLC7PP/98MUeyIs8SmFMHn3rqqZg+fXpje05BzAAt91394Ky//vrF+lhjxoxp0oesFJs1a1Y88cQTjW35QG+22WbF7T377LON7X379o0NNtggxo8fHy+99FJje87fzKqzN998M15//fVY4v0Pb3dO7yExq9/K0Wva69Fj5oTG7Wf3Xa649P7glaib/VGYN6vfSjGn99DoM/mFqJ07o7F9Rv/Vor7ngOj7/tNRUwQnH5o+cHg01PaMJSY2PUvitMGfjpr62dF30kd9b6ipjemD14/aOVOiz5SP+l5f1ydmDBwePWZNjF5TxzW2z+3ZP2b2Xz16zngnek5/q7G9O4xpzJi6Tvvcq+hKx5MxGZMxGZMxGZMxGZMxGZMxGZMx9W1xTJVgq0MvdJ5uvvnmOOqoo+Kqq66KbbbZpsnfbrnlljj11FOLs+lVe+CBB+Lggw+OF154ofg975jcbvfdd2+y3U477VRsd+CBB7a5UmqllVYqzuBXWYirMyeTzdtHj53WbaqKuuKYDthkiU773Gvex65wPBmTMRmTMRmTMRmTMRmTMRmTMRlTTYt9z1lrWSS0oIXO2zWUyvAnE7Xbb7891llnnXn+ntPzlltuuSLNyzPpVRx33HHFHX322WcXv2e1U64xdfnllzdukyldpoTOvvcRZ9/r3Jx9DwAAgM6gU5x979prr4199tmnxUAq5RS6nM6Xa0298cYbRRo3evTouO6662LkyJGN2x199NFx7733xqhRo4pkLrfNs/Edf/zxbQ6kAAAAAChPu4ZSWd30m9/8plgTqvnlxBNPLLbJ8GnvvfcupvZlynbJJZfErbfeWsyTrMhFzu+888645pprinmSOZ1vhx12KKb0AQAAANDxtPuaUh2J6Xt0ZKbvAQAA0Bl0iul7AAAAAHRPQikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAAuncotcwyy8T48eMbf3/11Vejb9++MWjQoHkub775ZpPrjhs3Lvbcc88YOHBgDBs2LE4//fSor69vh1EAAAAA0ClCqalTp8Z5550X7777bpP2hoaGqKuri/fff3+eSwZP1dffcccdY8SIEfHee+/F2LFj4/777y+CKQAAAAA6nnYPpS688MJYeuml46STTvrY+7jgggtio402isMPPzx69OgRyy+/fFx55ZVx7rnnFiEVAAAAAB1Lu4dSRxxxREybNi1mzJjxsfdxww03xP777z/PVMAtt9wybrvttkXQSwAAAAC6VCi1ILku1CmnnBLDhw+PoUOHxhZbbBE33nhjk22eeeaZWHPNNee57uqrr178DQAAAICOpUd0YLnI+TbbbBNDhgyJv/zlLzFgwICi8unggw+O0aNHx84771xs98EHH8TgwYPnuX5eb8qUKa3uf+bMmcWlYvLkycW/c+bMKS6ptra2uGQ4Vr1weqV97ty5xdpXC2rPtbFqamoa91vdnnL7trTn9MTcb3V77je3b97HedobKtepiaipjWjIbT/q40ftTW+z9fbavJGW2wv1bWuvqcsFxFppb97H1tq7/piaPyc71XOvWR+7xPFkTMZkTMZkTMZkTMZkTMZkTMZkTNFS35tft1OGUssuu2z8+c9/btK2xx57xA9/+MNiLapKKLXkkksWi5/nWlLVsi2DqdaceeaZLS6G/thjj0W/fv2Kn3O9q6y4evnll5ssxL7iiisWl+effz4mTZrU2L7aaqsVUwefeuqpmD59emN7VnrlWQNz39UPzvrrrx+9evWKMWPGNOnDpptuGrNmzYonnniisS0f6M0226y4vWeffbZJeLfBBhsUZy586aWXGtvzTIRrr712cabC119/PZZ4/8PbndN7SMzqt3L0mvZ69Jg5oXH72X2XKy69P3gl6mZ/FObN6rdSzOk9NPpMfiFq5340zXJG/9WivueA6Pv+01FTBCcfmj5weDTU9owlJj7ZZEzTBn86aupnR99JH/W9oaY2pg9eP2rnTIk+Uz7qe31dn5gxcHj0mDUxek0d19g+t2f/mNl/9eg5453oOf2txvbuMKYxY+o67XOvoisdT8ZkTMZkTMZkTMZkTMZkTMZkTMbUt8UxVYKtBalpqI7P2lkmbHlHL7XUUvPd7uabb44f//jH8eijjxa/5x1z6qmnxu67795ku5122qmoqjrwwAPbXCm10korFYujZ1VWZ08mm7ePHjut21QVdcUxHbDJEp32ude8j13heDImYzImYzImYzImYzImYzImYzKmmhb7nrPWskgoQ6xKvtJlQqljjjmmWBz9kksuKX7PaqcXX3wxLr/88sZtMqXLlDATxVyLqi0ylMqEckF3Wmd12SNT27sLfAJf3/zD6j0AAADoyNqar3Tohc5fffXVGDFiRDzwwANF4paD+vnPfx5XXXVVnHzyyY3bHX300XHvvffGqFGjiu3eeOON4mx8xx9/fJsDKQAAAADK06FDqWHDhsWuu+4aI0eOLOY/rrLKKsWUvb/+9a+x6qqrNm6Xi5zfeeedcc011xTb5XS+HXbYoZjSBwAAAEDH06Gm77U30/foyEzfAwAAoDPoEtP3AAAAAOiahFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDnCaUaGhpi4sSJi7Y3AAAAAHQLCx1K3X///TFz5syYMmVKbLfddounVwAAAAB0aQsdSv3617+OsWPHRv/+/RdPjwAAAADo8hYqlKqvr48xY8bEFltsETU1NdGzZ8/F1zMAAAAAuqyFCqVGjx4de+yxR9TV1RW/C6UAAAAA+Dh6tHXDxx9/PM4+++y45557PrpyjzZfHQAAAAAatSlVOvLII+Pvf/973HTTTTFo0KDG9gkTJsQvf/nL4kx8c+bMKRZAnzFjRuy9996x0UYbtWXXAAAAAHRDCwylZs2aFePGjYtevXpFv379mvwtg6j333+/6Q579Gic3gcAAAAAHyuUyjDq5ptvjjvuuCN23XXXuPvuu6Nv377F37Jq6rTTTlvQLgAAAADg4y10vuOOO8bBBx8cp556amNbTtsDAAAAgIW1UCuVf/vb347NN9+8WDeqT58+xdQ+AAAAAFhslVIV2223XeMZ+DKcAgAAAIDFWimVDjjggFh11VWLn4VSAAAAAJQSSm200UaNP993330f60YBAAAA6N4WevpetVVWWWXR9QQAAACAbqNNlVK33HJLLLHEEsXPNTU1je2Vn6vbhgwZEuutt96i7ykAAAAA3SuU+u///u+ora2N+vr64jJ37ty49dZb4/Of/3w0NDQUbflvXtZcc02hFAAAAACfPJT63e9+N0/bFltsEVdccUVbrg4AAAAACx9KXXzxxdGnT5/o0ePDzbMy6r333otRo0ZFXV1dk2333Xffxql+AAAAAPCxQ6kZM2bEzJkzi2l7lel7hx12WLz11luN0/cqU/imT58ulAIAAADgk4dSRx99dFs2AwAAAIBFF0qln/70p0Ul1Pbbbx//+q//2uSMewAAAACwMGrbuuFNN90Uyy+/fFx00UWx9tprxy9/+cuYM2fOQt0YAAAAACxUKNW7d+/41re+FVdeeWU8/PDD8fbbb8eWW24ZL7/8snsSAAAAgMUTSlWfZW/gwIFxxhlnxPnnnx8jRoyIcePGLdytAgAAANCttTmUyjPwNbf11lsXwdTee+8ds2fPXtR9AwAAAKC7h1KHHHJIi+077bRTfPazn41XX311UfYLAAAAgC6szWffO+yww1r921lnnbWo+gMAAABAN9DmSikAAAAAWFSEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUrkdbNvr+978fPXv2bPXvc+bMKS719fUxe/bs2HzzzePAAw9clP0EAAAAoLuFUjU1NVFbWxu9evWKHj16FD9X2jOIamhoaLzk7wMHDlzc/QYAAACgq4dSZ5xxxuLvCQAAAADdRpvXlPr2t7/dYntO29tvv/1i8uTJi7JfAAAAAHRhbQ6lrr766nnacrreoYceGlOmTIkBAwYs6r4BAAAA0N1Dqco6UhVPP/107LDDDvH666/Hddddtzj6BgAAAEB3XlOquipq0KBB8fe//z2efPLJOOGEE+Koo46Kurq6xdtLAAAAALpnpVSede+zn/1sDB06NCZOnBiDBw+ODTbYQCAFAAAAwOKrlOrZs2d85StfKX4+6aST4r777osjjjiiaPvhD3+48LcMAAAAQLfV5kqpuXPnNvl92223jUceeSTuvffeOOWUUxZH3wAAAADo7qHUvvvuO09bv3794vrrr49rrrkmXnvttUXdNwAAAAC6+/S9X/3qVy22DxgwIO6+++4YNmzYouwXAAAAAF1Ymyul5kcgBQAAAEDpoRQAAAAALNLpe7fddluMHj066urq2rQY+uzZs4vtAQAAAOBjh1LLLrtsbL311tG7d+/o2bNnEU7V1tYWl5qammKbhoaGqK+vjzlz5sxzlj4AAAAAWOhQasMNNywuAAAAALCoWFMKAAAAgI5XKVXtlFNOiR49ehSXnLJXma73k5/8ZPH1EAAAAIDuXSl1wQUXFIFUyvWkco2p888/f3H1DQAAAIAuaqEqpZZaaqk4+eSTm7T99re/XdR9AgAAAKCLW6hKqTwDX3O9evValP0BAAAAoBtYqFAq15BqbubMmYuyPwAAAAB0Aws1fe/NN9+MQw45pPH3XOx8/PjxUV9fH7W1TuQHAAAAwGIIpc4+++xicfMMoPKse1k5teWWWxaLngMAAADAYgmlDjvssIXZHAAAAABaZM4dAAAAAKUTSgEAAADQMafvfe5zn4u6urpiQfNc3DwvlZ9bajvrrLNiu+22W/y9BwAAAKDrhlLf/e53o3fv3tGrV69iofNc2LxyaSmUWmuttRZ/zwEAAADo2qHUF7/4xcXfEwAAAAC6DWtKAQAAANCxQ6m//e1vse+++8bKK68cffv2jRVWWCH22GOPuOeeexZfDwEAAADovqHUXXfdFXvttVfsuuuu8eCDD8bkyZPj8ccfj29+85txzDHHxP/+7/8u3p4CAAAA0L3WlErnnHNOXHHFFfGZz3ymsW2ppZaKPffcM9Zdd91iMfQRI0Ysrn4CAAAA0B0rpd55551Yf/31W/zbgAED4r333luU/QIAAACgC2tzKLXddtvFeeedN097fX19/PCHP4xtt912UfcNAAAAgO4+fe9HP/pRHHjggUW1VE7hGzx4cFE9deutt8aGG24Y55577uLtKQAAAADdL5Tq169f/PGPf4wnnngiHnrooXj33Xdjs802i2OPPTbWWWedxdtLAAAAALpnKFWRlVKtrS0FAAAAAIt0TSkAAAAAWFSEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAAB071BqmWWWifHjx8/TftFFF8Vqq60W/fv3j2233TaefPLJebYZN25c7LnnnjFw4MAYNmxYnH766VFfX19SzwEAAADodKHU1KlT47zzzot33313nr9dfPHFMWrUqLjrrrti0qRJceSRR8Yuu+wSb7/9dpPr77jjjjFixIh47733YuzYsXH//fcXwRQAAAAAHU9NQ0NDQ3t24MILL4zjjz++qGqaOXNmEUwttdRSxd9mzJhRVD09+OCDMXz48MbrHHPMMdGrV6/4xS9+Ufx+1llnxWOPPRZXX3114zbvvPNOrLHGGvHyyy/H0KFD29SXyZMnF5VWGX4NGDAguprLHpna3l3gE/j65v3auwsAAACwyPKVdq+UOuKII2LatGlFANXcPffcEyuvvHKTQCrtt99+ceONNzb+fsMNN8T+++8/z1TALbfcMm677bbF2HsAAAAAPo4e0YE988wzseaaa87Tvvrqq8eLL74Ys2fPjp49e853u/xba7IyKy/VSV6aM2dOcUm1tbXFJSu5qteoqrTPnTs3qovNWmuvq6uLmpqaxv1Wt6fcvi3tPXr0KPZb3Z77ze2b93Ge9obKdWoiamojGnLb6kK5SnvT22y9vTZvpOX2Qn3b2mvqIor7qqX25n1srb3rj6n5c7JTPfea9bFLHE/GZEzGZEzGZEzGZEzGZEzGZEzGFC31vfl1O2Uo9cEHH8TgwYPnaR8yZEhxR+RaUoMGDZrvdlOmTGl1/2eeeWaL607lVMB+/T6cKrX00ksX4VZOA6xe82rFFVcsLs8//3xRjlaRC7JnldZTTz0V06dPb2zPaq/sa+67+sFZf/31i6mIY8aMadKHTTfdNGbNmhVPPPFEY1s+0Jtttllxe88++2xje9++fWODDTYoFol/6aWXGtuzVG7ttdeON998M15//fVY4v0Pb3dO7yExq9/K0Wva69Fj5oTG7Wf3Xa649P7glaib/dH9NqvfSjGn99DoM/mFqJ37UUXbjP6rRX3PAdH3/aejpghOPjR94PBoqO0ZS0xsuiD9tMGfjpr62dF30kd9b6ipjemD14/aOVOiz5SP+l5f1ydmDBwePWZNjF5TxzW2z+3ZP2b2Xz16zngnek5/q7G9O4xpzJi6Tvvcq+hKx5MxGZMxGZMxGZMxGZMxGZMxGZMx9W1xTJVgq8OvKVUtE7bqNaXOPffceOihh+IPf/hDk+1ym2WXXbaocspKqXwAc7t8EKsdddRRRTD1k5/8pM2VUiuttFKxWHplzmNnTiabt48eO63bVBV1xTEdsMkSnfa517yPXeF4MiZjMiZjMiZjMiZjMiZjMiZjMqaaFvueBUKZxyxoTakOXSmVU/KuuOKKedozDcy0MAOpynY5na95KJXbHXzwwa3uv3fv3sWlubyj81Kt8uA211r611p78/1+nPZ80Ftqb62Pje0ZfDTZUStLijXf7uO2x0K0ZxDUYntrfVzY9s4/puaPead67rWx3ZiMqbV2YzKm+fXdmIzJmIxpfn03JmMyJmOaX9+NKRbLmFrrwzzXiw5s++23L4KlDJyqXX/99bHnnns2/r7bbrvFNddc02SbLB17+OGHY+eddy6tvwAAAABE5w+lcl2nU045JQ466KB44403ihKx0aNHx3XXXRcjR45s3O7oo4+Oe++9N0aNGlWUi+W2eTa+448/PoYOHdquYwAAAACgk03fSxk+ZdnXNttsU1Q/5cJat956a7F4V0Uucn7nnXcW4dQxxxwTSy65ZLGe1A9+8IN27TsAAAAAnWCh8/aWC53noukLWoirs7rskant3QU+ga9v/uEZIQEAAKAr5CsdevoeAAAAAF2TUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0nX4UOrQQw+N/v37x6BBg5pcjj766CbbXXTRRbHaaqsV22677bbx5JNPtlufAQAAAJi/HtHBzZ49O0477bQ44YQTWt3m4osvjlGjRsVdd90VK6+8clxzzTWxyy67xNixY2PZZZcttb8AAAAAdIFKqQWZMWNGnHTSSXHppZfGqquuGrW1tbH//vvHPvvsE2effXZ7dw8AAACArhhK3XPPPUV11PDhw5u077fffnHjjTe2W78AAAAA6MTT99Kjjz4aI0aMKP7t169f7LTTTnHWWWfFkCFD4plnnok111xznuusvvrq8eKLLxbT/3r27NnifmfOnFlcKiZPnlz8O2fOnOKSsvIqL/X19cWlotI+d+7caGhoWGB7XV1d1NTUNO63uj3l9m1p79GjR7Hf6vbcb27fvI/ztDdUrlMTUVMb0ZDbftTHj9qb3mbr7bV5Iy23F+rb1l5TF1HcVy21N+9ja+1df0zNn5Od6rnXrI9d4ngyJmMyJmMyJmMyJmMyJmMyJmMypmip782v22lDqXXXXTf+9re/FetKbbzxxvH2228X60vttttu8cADD8QHH3wQgwcPnud6GVjlnTV16tRiYfSWnHnmmXH66afP0/7YY48V4Vdaeumli4Dr5ZdfjnfffbdxmxVXXLG4PP/88zFp0qTG9lxsfZlllomnnnoqpk+f3tielVzZj9x39YOz/vrrR69evWLMmDFN+rDpppvGrFmz4oknnmhsywd6s802K27v2WefbWzv27dvbLDBBjF+/Ph46aWXGtsHDhwYa6+9drz55pvx+uuvxxLvf3i7c3oPiVn9Vo5e016PHjMnNG4/u+9yxaX3B69E3ewpje2z+q0Uc3oPjT6TX4jauTMa22f0Xy3qew6Ivu8/HTVFcPKh6QOHR0Ntz1hiYtPF5qcN/nTU1M+OvpM+6ntDTW1MH7x+1M6ZEn2mfNT3+ro+MWPg8Ogxa2L0mjqusX1uz/4xs//q0XPGO9Fz+luN7d1hTGPG1HXa515FVzqejMmYjMmYjMmYjMmYjMmYjMmYjKlvi2OqBFsLUtNQHZ91ElndlA/A7bffXkzfe+ihh+IPf/hDk23yActFznPbhamUWmmlleK9996LAQMGdPpksnn76LHTuk1VUVcc0wGbLNFpn3vN+9gVjidjMiZjMiZjMiZjMiZjMiZjMiZjqmmx71OmTCmKhTLEquQrXSaUSptsskn8+Mc/Ln4+9dRTizPtVcsqqoMPPjheeOGFNu8zQ6lMKBd0p3VWlz0ytb27wCfw9c0/rN4DAACAjqyt+UqHn77Xkn/84x9FudinP/3pGDp0aFGylutHrbHGGo3bXH/99bHnnnu2az8BAAAA6KRn38v1o84555xiOl6WgmVFVK4ndcQRRxRn3cu1n0455ZQ46KCD4o033ijKyEaPHh3XXXddjBw5sr27DwAAAEBnrJTKsOm8884rFjmfMGFCEUR95zvfiSOPPLJxmwyfcg7jNttsUyyulYtv3XrrrcUCXwAAAAB0PJ12TanFwZpSdGTWlAIAAKAr5SsdfvoeAAAAAF2PUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAqAhfb222/HIYccEiussEIMGjQottlmm7jjjjvau1vQpTnuAICuRigFwELbddddY8iQIfHss8/Gu+++G0cccUTstdde8fTTT7d316DLctwBAF1Nj/buAACdy0svvRQvvvhijBkzprHtq1/9alx77bVx//33x7rrrtuu/YOuyHEHAHRFKqUAWChZqTFjxox45ZVXGtsmTZoUTzzxRGy22Wbt2jfoqhx3AEBXJJQCYKHkWjZnnHFGsZ7N2WefHVdccUUxrej000+PjTfeuL27B12S4w7a19VXXx0bbbRRDBw4MNZYY4047rjjoqGhob27BdDpCaUAWGj77bdfUZ0xatSouOaaa4rqjaeeeiqmTZvW3l2DLstxB+3jnHPOiZ/97Gdx4YUXFhWK9913X/Tv3z/q6+vbu2sAnZ5QCoCFcvvtt8fWW29dnAUsF1i+6aabiilEL7/8cuyzzz7t3T3okhx30D6ef/75okoxz3S55ZZbFm3Dhg0rqhTr6urau3sAnV5Ng7rTRpMnTy5KcvMbkAEDBkRXc9kjU9u7C3wCX9+8X3t3AQr5pjynLXz5y1+e5//QwYMHF6etX2qppdqtf9AVOe6gfYwcOTJmzpwZv/zlL9u7KwBdMl9RKQXAQqutnffl4/XXX4/evXvHkksu2S59gq7OcQfle/DBB4u13C699NLYdNNNi/B3q622ij//+c/t3TWALkEoBcBCOfzww+PYY4+N2267LWbNmlVc7rrrrth7773j1FNPjT59+rR3F6HLcdxB+3jnnXfi/PPPj5tvvjkuv/zyePPNN4vqqZw2O3bs2PbuHkCn16O9OwBA5/KNb3yjKMXN9TQOOOCAonpjnXXWKc4Itttuu7V396BLctxB++jVq1dxrF188cWNbXvttVc89NBDcckll8Qmm2zSrv2DruiBBx4owuB77rknpk+fHuuuu26ceeaZsf3227d311gMhFIALLSszsgLUB7HHZRvrbXWilVXXXWe9gyqrrrqqnbpE3R1xxxzTHznO9+J3//+90UwnJWKWZ3417/+NdZcc8327h6LmOl7AAAALcgPwr/73e9ixowZTdrHjBnjwzEsJlkhdfDBB0e/fv2iZ8+exRcyX/rSl4op7HQ9QikAAIAW7LfffvGpT32qmLL3yiuvFOu5XXHFFTF69OiimgNY9Fo6eUdO48uQiq7H9D2Axe2Wn7R3D/i4dj2lvXvAx3TOm5e1dxf4BI4b9vX27gIU6urq4qabboqTTz45tthii/jggw+Kf++4445YffXV27t70OWNHz++OMlAnljg17/+dXt3h8VAKAUAANCKJZZYIs4999ziApS3nts//vGPmDp1anGG2bPOOsuZZrso0/cAAACADuO5556LyZMnF1NmH3744bj++uvjqKOOau9usRgIpQAAAIAOOYV2vfXWi1/96ldx9dVXt3d3WAxM3wMAABaN//pte/eAj+vgb7V3D6BVb7zxRgwcOLC9u8FioFIKAAAA6BB23333+OMf/xgzZsyIOXPmxN133x2HHnponHrqqe3dNRYDlVIAAABAh3DMMcfE+eefH9/61reivr4+hg8fXpx5b8SIEe3dNRYDoRQAAADQIey4447Fhe7B9D0AAAAASieUAgAAAKB0pu8BAABAJ/X4He3dAz6uDcxS7FqVUuPGjYs999yzOFXksGHD4vTTTy8WRgMAAACgY+kyodTUqVOLxdByRf733nsvxo4dG/fff38RTAEAAADQsXSZUOqCCy6IjTbaKA4//PDo0aNHLL/88nHllVfGueeeW4RUAAAAAHQcXSaUuuGGG2L//fdv0rbMMsvElltuGbfddlu79QsAAACALhxKPfPMM7HmmmvO07766qsXfwMAAACg4+gyZ9/74IMPYvDgwfO0DxkyJKZMmdLidWbOnFlcKiZNmlT8O2HChJgzZ07xc21tbXHJBdOrF02vtM+dOzcaGhoW2F5XVxc1NTWN+61uT7l9W9pzamLut7o995vbN+9j8/bpH0yr/OWfeWRu+1EfP2pveputt9f+828ttaf6NrbX/bMfLbU372Nr7V1/TBMmzOy0z73mfewKx9NCjWnqR//P1EZD1NZEzG2oafJo10VD1NREzGnIx71pe9H3aFt7j5qGyLuquj1/qqtpiPqGfDYtuD2fdbVFe02TZ3Brfe/SY5o4sXM/97ri8dTGMc2YMj1qmv1X3vDP/7Jr6tvY/s//ypu01/xz+9ba6yNqqp5MxdN/Pu3FPqrb//ky1Gp7NxnTpH6TOu1zryseTws1punTP2xv4UNHQ7P24v/sf77TqW9De/F/+Xzac98NbWiv++dtNB3Rh+0t9b219i43pgkTOvdzryseT20c0+QPit5HbU1dNDTUR0OzZ19L7TVRGzU1ta221zc0fZa13v7hmOobmo4p21NDs2dfa+21NR+OqWl71x/ThAmd+7k3v75XcpjqfnTpUGrJJZeM999/v1hLqlq2ZTDVkjPPPLPFhdA/9alPLbZ+wsf17fbuAHRLZ7R3B6BbOtmrHpTvyKPbuwdAF5Th1MCBA7t+KJVT91588cVYe+21m7Q///zzcfDBB7d4ne9///tx3HHHNf6eqV5WSQ0dOrRI++g8Jk+eHCuttFKMGzcuBgwY0N7dgW7BcQftw7EH5XPcQftw7HVeWSGVgdSwYcPmu12XCaV22223uOaaa2L33XdvbBs/fnw8/PDDcfXVV7d4nd69exeXaoMGDVrsfWXxyf+o/GcF5XLcQftw7EH5HHfQPhx7ndP8KqS63ELnRx99dNx7770xatSoouLpjTfeKM7Gd/zxxxeVTwAAAAB0HF0mlMpFzu+8886iWiqrnTbbbLPYYYcd4tRTT23vrgEAAADQVafvpX/5l3+JP/3pT+3dDdpBTsM87bTT5pmOCSw+jjtoH449KJ/jDtqHY6/rq2lY0Pn5AAAAAGAR6zLT9wAAAADoPIRSAAAALTj//PNj4sSJ7d0NgC5LKAXAYjNnzpyYMWNGfPDBBzF37tz27g4AzNfMmTOb/H7WWWcVr2MLY9VVV42XXnppEfcMOqf6+vpW22fPnl16f+h4hFJ0aM8//3wccsghsd1228WBBx4Y999/f5O/33TTTbHPPvvM8x/cxRdfHJ///OeLszBuuummsfHGG8enP/3p+NrXvhZ/+9vfSh4FdC75BuG73/1ufOpTn4rhw4fH73//+6L9//2//1ccS2n77bePu+66q/E62267bay//vqNx9xGG21UXLbeeuvYcccdY4UVVojHHnus3cYEnUUedwv7YfYnP/lJ/OhHP2rStuuuuxYngFl33XWL1788PjfccMPi56OOOqrYZuTIkfH9739/kfYfOpPdd989/vKXvzRpy7N3//Wvf238vU+fPlFTU9Pi9X/6058WZ/9uLr+EsSgzRNx3330xYMCA4j1hvj/caqutYptttonNN9+8eM+Y7ycXRi6H3b9//+Lfavn+dIsttijej37mM58pbiNvq/ozZb4fpWPqUmffo2t57bXXiv+oLrzwwvjc5z4XDzzwQOy2225xyy23FP/RpF69ekXfvn2bXO+MM84o/gP8r//6rxg2bFiTio3bb7899thjjxgzZkwst9xypY8JOoN///d/j7q6uvi///u/osJpp512Kt44ZNvgwYOLbXr06FG8yajIY25+8sPwkCFDFnvfoSPLN82TJ08ujp/Klyh5jGXgu8wyyzR+AK6t/eg7w4suuij+4z/+o2jPYzBfy3IfL7/8cvF7yg/MlX1W/M///E/xpj33deyxxxb/nnPOOcXfch+pZ8+exQW6qzwu3nvvvRg/fnxxPGaYlJfq95bNj61q+dqXH7Sby2Mz36NCd5evMfke8u67727zdR5//PE488wz4/XXXy++WDn55JNj5ZVXbny9q1yqPfLII02O1bfffrv4zFeRx6Pzu3VcQik6rD/84Q9x6KGHxp577ln8/oUvfCGOPPLIuOyyyxpDqVR5U16R4dVhhx3WJJBK+R/ViBEjim+Ln376aaEUtOKPf/xj3HvvvcWb9QyessLwnnvuKb49rn4T0Nob9ffffz+eeOKJ4tuqin/84x9FtRR0Z/mFSHXglB9+Bw4cGEsttVSrr2nf/OY349vf/naTtpVWWmmBb66r37Q/99xz0a9fv3mO3fx3fh+4oavLY+SHP/xh8YVLHptZKfzMM8802WZ+wW0eW9XHdPVx3Fp1FXQnrU3dq5g1a1ZxjFWOl6wU/tKXvhSXX355rL322jF69Oji/edTTz3VGBa3dEw2fy279tpr4+tf/3qTNstIdFzeidBh5Yv8Ekss0aQtA6Wbb765mFqUH5qnTZsW//qv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7vrrr2/8OW8/A5illloq7r777lgY77//fpxwwgkxceLEYpzTp0+Pn/70p0VYUpHj7NmzZ5Pr/fd//3dceOGF0a9fv2KcGYKdccYZjX3N9iWWWKJNffje974X3//+92OnnXZaqL7fcccd8R//8R8xfvz42GGHHeLUU0+NJZdcsvHv2Zfmj12GRdn3vn37FuPKvlequvJxz9/z/sxQaOedd57v7e+3335FMHjzzTfHsssu2+Q+/c1vfhNf+MIXikq7irxv8/HJ59Qvf/nL4nbz9l577bV46aWXYscddyz6lX/v06fPQt0XAMDCUSkFACwyBx54YBGE3H777XHSSSfFN77xjRgzZkyTgKL5lLIMDvr37x9rrrlmrLPOOrHGGmvEoEGD4oc//GHjNs3DmPTrX/+6qIJ566234vzzz4999tmnCHWy2icDqcrtLcjpp58ezz77bDz11FPx97//vfh51KhRRShRkYFV82ClWoYa3/nOd2Ldddctqpl+9rOfLdTUsG9/+9uxxx57FCHXNddcE7/61a/iq1/9ahGKfeYzn4ltttkmJkyY0OQ6jzzySBEG3XjjjfHHP/6xCGVWXXXVJpVZeb+NHDmyqCD6y1/+Mt8+5Hhbup/nJ/tw1FFHFUHY//7v/8bUqVPja1/7WpNtWnrMzz333CIEeu655+KZZ54pHusMNCu/Z9XSk08+2aaqugcffDBOPvnkJoFUyudQVsm98cYbMWnSpMb2GTNmxP33319cLy85hoceeqj4Oe+j7EclEJ3fYw4AfHJCKQBgkcjpX//3f/9XhDyDBw+ObbfdNk477bQ488wzG7fJ0KN5WJNtGSg9//zzRSj04osvFlVDGQRVLCgcePXVV4sQornqfbSmpcqtDCcyCKq+/Zb2ldU8GcBlcJTTwa644oqiAui2224r2jJkyqCsLfddhlIVK6+8clH1lBVH2ZecPjhgwIAm18m2rCKqroTac889m0yVy37/+7//ezzxxBNFfxb2fliQfGyzoisrxLIyLiuPcix5e/N7zCsVcBVZ8ZbT8DLYyhArg818DrUlVPzud79bVHdlmPePf/yjCAVzXxmGHnbYYcXjOHDgwMbtc78ZomUF1QsvvFBUemUl1b/8y7/Ez3/+89h7772LKX352DXvJwCwaJm+BwAsEllt0jz4+PznP19M56vID/nNA4rWwpDqEGhBgclNN93UYij1cYKWmTNnFlPi/vSnPzXpd/NgLMOPDN5yqlcGcZVpb7mm1H333VdULmXIkQFVpXKrNRmaZEXPCius0LjvDPhWX331osoox9G82mjLLbcsQpdvfvObxVTD/Psll1wSW2yxReM22fbXv/61uC/zsVlllVVa7UNuO7/qrqwGy/uh+j7Nx7x6zaq8nZzC9+ijjxbVWZX7bn77zbXCctpcVntlZV2uB5XVcm31k5/8JHbddde46qqr4oILLiimEWblXe5jr732KkKm5vK+zr9ddtllsdVWWxXVdrk+WAZ/lYqyDLsydAQAFh+hFACwSLz77rtFFUq1nFJVvdB0BhTNw5XW1nyqDjLmFy5lAJTTxsaNG1dM+coFrj+J//zP/4zNNtusmEpYrXkolX3KwKc1u+++e3HJcWTQVT0dsKWpiDldL0O8yvTHXJspK3lyWmCGPblGUvU6WxmmZBiWVWYZYmWAsvXWW8d5553XuN9sy0qtnJK2oLW18rHKdbpynLntyy+/XEwHzMcr95/T3i699NKij5/0MU8ZHmVol2FUjjdvKyuYMjzLIPPggw+e733WPKDLS1vl9MDVVlutcb2z/HmXXXYppg9mW441K/c23XTTNu8TAFh4QikAYJHICqFcn6daruUzZMiQxt9bqppprRqlur21aVQZRuV6TLkGU04bywDnrrvuagyQFnb6Va4rlFVNueZQteb9zmlim2yySTF1LqenZWiUU80yOMp+532RQVQuqp19zHAlQ57WbLzxxkVFVYZqGYhkIFOZrle5T7MSrDqUSlkF1FIlUEX2Zfvtty/uowX5r//6rya/5yLfub7W/OQ4M4BaccUVmzzm1RVZze+7/PmII44owqgM4nKaXWWseca7DIJySuCPf/zjuPzyy1tdVyqnSeZ6WSlDtAwlM9iqyH5lxVTuO0OxDK0yVEtZTZZrWuV6WFntllNG83G/8847i31mn7MKTaUUACxeQikAYJHItXtyKlV+kK9MvcuQJ8ObisqZ7aplSJHrAWWYlOFNVuW89957cfTRR8/39nJB8wxk8uxrOWUsK2xyylxOZ8tpbBkWtVSh05rRo0cXFTq5cHiGLdWa93v55ZePN998s8U1lnJqWE4jW1gZauX0vZzOlguYZ6iSbRnw7LbbbkVlUUsVY9mvG264IW655ZYiaMkgLIPADLpyzams+vo42rKeUz7mebuHH354Y1s+5jkNr7X7LgOfDJ1y/amWKqGyQi0fi3wezG/h9epALu/zfJ5luFRx0EEHFVVPGXS1NF0y173Kvr/++uvF/Z6h5nLLLde4zdChQ4tQCwBYfIRSAMAikWee22CDDYqqnDz7XC42fcoppzSZTpYBVPNKqUMPPTS+9a1vzbOQePPqmmoZQmQQte+++xaLqae8fgZKX/rSl+KAAw6Ia6+9trjegqpdMgzLaWMZluTZ7nJ9puayEqelgCunr2U1UWUtrZbG11ZZSZVVQccdd1ycc845RfCV+8r2nOaWa1z99re/ned6hxxySDE9L89Al4t1Z9CTFVu53lPu6w9/+EOstNJKC92fadOmLXCb448/Pr74xS8Wa1/ldMKsNsrAp3raW0v3yVJLLbXAfS/MmQBbm945v0q57GdO9cz1yHLaXp4RsHKdDKRyjam8AACLj1AKAFhkcrHpDImysierdTKcqp5+1VJA0dqZ9aoDheaBUFa2VNYhqpZnq8szuOUUssrtzS+UymqcrK7KaVy58HVrch8thVK5NlEGb5XFsXMsbakwakn2e8SIEcUC29Vy4e/zzz+/WKuppVAqzxKX1T7VZ5jLM+Hlela55lXuN6umWnPSSScV1Vk5FbEyHbEyXTDXqMqx56UyHTHDwN/97nfFNpUpcWeffXZR3ZbBVFZtVWv+mFcWbm+LfHzaElC1FAQ2n+rYkjxbYZ4xMcdZLcfyla98pZj6l/8CAIuHUAoAWGRyulNW+bSmpel7bZGhSPOFupsHUhUZRFTOxJfBxPxuL8OOSoXM/MyaNavF/WQIVT0F7cQTT4yPK4ORnNKW08iy4qwig6BcfL35mQ0rcoparql1wgknNAnEcn2qrBzLqYzzk2s35bTLtlQmVRY9r/aFL3yhuMzvOtX3XVZV5fpPuWZVZT2uyln9KtvmY52PeT5+Obacijc/zfuU2lKxlovKZ6VbhnbZn4rK7VcHfQDAoieUAgBK83Gnt2VI0FLw8HFClI8jQ6mWqm5y33n2v6xiynClMgUxbzevk5f1118/7r333gXexkYbbRSjRo0qQqI8614l9MrgZtddd43rrruuxetlpU9Wp2WwkkFKhjt5H2dolxVWzauAmluYyq7cd1vPiNfaY/7MM88Ut9nWaqm2qIx7frfbklxcPqu8ssIrw798nuVjmGuK5bTSrFwDABafmoaPu/ABAMBCyrPWZWVKTgErQ64XlFP5vva1r32i/bQ2FawSfMwvYKle+L07uuOOO4pgrvni8YvbU089VVTMVZ8ZEADoWIRSAAAAAJRu0dVNAwAAAEAbCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAiLL9f0C/EK51pCiwAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nutrition_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\", \"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\", \"์˜์–‘ ์ •๋ณด ์–‘์‹\", \"์˜์–‘ ์„ ๋ช…\", \"์˜์–‘ ๋…ธ์ด์ฆˆ\"]].copy()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\")][\"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=30, ha=\"right\")\n", + "plt.xlabel(\"์ƒํ’ˆ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์˜์–‘ ์ •๋ณด ์–‘์‹\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\")][\"์˜์–‘ ์„ ๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์„ ๋ช… ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"]==\"O\")][\"์˜์–‘ ๋…ธ์ด์ฆˆ\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ๋…ธ์ด์ฆˆ ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์„ฑ๋ถ„ ์ •๋ณด (์ˆœ์„œ ์œ ์ง€ O)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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WrXIHKhVq1bZM888E6mOUmil1rytW7fa888/7y17ojBKwVaolFILnyqoNBR9xIgRVrJkSW8HLFy4cI7tLwAAAAAAyNuolMrjQqaoQEotdd27d7drrrnGW/G+/vrryPX69+/vIdKll14auZ1a+NTa98033/icqD59+vjgcw1AVyCl++vatau3/WlFvrFjx3ogJQRSAAAAAADgUBBK5XGhVU/tedWrV/cKJoVM48aNs7lz50auV69ePa90euSRR5Lc7oorrvDv69evt23bttmMGTP8tK6n66sCS5VXd911l58fhp0DAAAAAAAcCkKpfEAr5r3//vv2xhtv2JgxY/w8zYbSnKgwqDxcb9GiRZGZUtGqVq3q7XsPPvignXLKKTZt2jR7++23/f6KFSsWCaNCiyAAAAAAAMChYPW9fECtdfqKtmXLlshqexpUruqpBx54wDZt2hR31bxjjjnG6tSp46GVqqratWvn54fB6YRRAAAAAAAgMzHoPB/5448/7IgjjrDHHnvM2/k2btzo7XwKo2bOnGk9evSwG264wU8rsDr//PP9dvonENr5oqV0PgAAAAAAwKGi/CUfUSC1ZMkSnyX11FNPeUufBptrKPns2bOtRIkSVr9+fZ8ddd5559nq1av9drHBU8gpCaQAAAAAAEBWoVIqH9m6datVq1bNLrroIm/ZUwufKqTUspeYmGiFChWy4cOHe/VUly5drEaNGjZo0CBv3QMAAAAAAMhOhFL5zHvvvWfNmjWzN99800aOHOlzoubPn28DBw60iy++2O69915fYa9nz54eTAEAAAAAAOQE2vfyGQVS0rRpU6+MWrNmjc2ZM8dWrVplNWvWtCJFitjSpUsjgRSZJAAAAAAAyAlUSuVjH374oXXs2NFKlSpllStXthEjRliFChUiq+qxoh4AAAAAAMgphFL5fDW+oUOHegtfo0aN/DzCKAAAAAAAkBsQShUQrKgHAAAAAAByk0I5vQHInkCKMAoAAAAAAOQm9HEVAARSAAAAAAAgtyGUAgAAAAAAQLYjlAIAAAAAAEC2I5QCAAAAAABAtiOUAgAAAAAAQLYjlMonDhw44KvsZYd4j/PHH3+kebv0XCc9/vvf/8bdhtT2f/fu3X67/Oz333/PtOcYAAAAAICsRiiVS9WtW9c+//zzZOdXrFjR1q9fn+z8Nm3aWM2aNe3SSy+1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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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pCY1qUlNalKTmtZwTc09sViLh1IvvPBCucMxqinWkor1fi6//PI8BWvmzJnLXSfaIngIsU2ceS1GwPTo0aPJ7RoTwcbZZ5+9XHusR1WaQhhTvGLEVQQaU6ZMKW+zySab5EuEJzFHsiQW3F5//fVzDdGnkqFDh+ZpiNVnfRs+fHgO1caPH9+gD7F4d9T15JNPltvigY5Fv+P2nn/++XJ71L3ddtvl0WaxaHxJzN+MNbkmT56c19YqaQs1HXPMMenCCy/MZ9ZrrKaoJ578pcevVNM///nPBttHPV/4whfyFMDqmoLHSU1qUpOa1KQmNalJTWpSk5rUpKY1W1Nz1/Zu0YXOG/Pss8+mXXfdNQdKP//5z/N0rJtvvrnBNnHWtTirWpxlr/RAxXbbbrttg+3e97735e2aWpOosZFSMaom1jMqLcTVlpPJ9pi2qklNalKTmtSkJjWpSU1qUpOa1KSm2lZdU8xai9lrK1vovNWFUhE0xciW1157LaeBkdzFWfgqizj44IPzAugxJSt89rOfzSnhOeecU94mEr04Q1+kjHHHNYez7wEAAAC8O83NV1p0+t6BBx6YPv/5z6d99903B0d//etf8wLUcQa18N73vjcdddRReaHqX/7yl3mq3s9+9rM8VGzcuHHl/XzrW9/K6wONGDEi7b///nlK4NFHH53Xp2puINURXP3ovJbuAu/C0bu8PaUUAAAA2oMWPfveqaeemn71q1/lUU4x7zHCpUsvvTQHVSU/+clP8vzHbbbZJq277rrp/vvvz6OpSouhhy222CLddttteY2oWEMqQq5YDDvWJQIAAACg9Wl10/daUnufvmekVNtmpBQAAADtKV9p0ZFSAAAAAHRMQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAACieUAgAAAKBwQikAAAAAOlYoVV9fn2666aa07777pg033DCtt956adSoUemFF17Iv3/ttddSjx49Ur9+/Za7TJ48ucG+Jk6cmK/bt2/fNGjQoHT22Wenurq6FqoMAAAAgFYbSs2aNStdcsklacyYMenVV19Nr7/+evrQhz6U9tlnnzRnzpwcWnXq1CnNnDlzuUsETyXz5s3L1xk5cmSaNm1amjBhQnrggQdyMAUAAABA61NTH8lPCynddE1NTYP2bbbZJodVm2++ef7/3LlzV7if888/Pz3++OPp+uuvL7e99dZbaYsttkivvPJKGjhwYLP6M3v27DzSKsKyPn36pPbm6kfntXQXeBeO3qVnS3cBAAAA1li+0qIjpSKMqg6klixZkqZPn75KodAtt9ySDj/88AZt66+/fhoxYkS6884711h/AQAAAGiHC53HyKlTTz01DRs2LO200065LdaFOvPMM9PQoUPziKcPfvCD6dZbb21wveeeey5tueWWy+1vyJAh+XcAAAAAtC6dUysxY8aMdMwxx+S1pGLkU4hFznfbbbc0YMCA9Ne//jWPnoqRT8cee2waN25cXiA9xPS+/v37L7fPuF7srymLFi3Kl8rhZWHp0qX5Empra/MlwrHKhdNL7cuWLStPQ1xRe6yNFaPCSvutbA+xfXPaO3funPdb2R77je2r+7hce33pOjUp1dSmVB/bVs7eLLU3vM2m22vjRhpvz+qa117TKRLJJtqr+9hUe/uvqfo52aaee1V9bBfHk5rUpCY1qUlNalKTmtSkJjWpKTXW9+rrtupQ6tFHH01HHHFEOuqoo/KoqLgTwwYbbJD+9Kc/Ndj2oIMOSt/+9rfTZZddVg6levXqlRc/32ijjRpsG20RTDXlvPPOa3Qx9FifqmfPt9fviTMCxoirWJtqypQp5W022WSTfHnxxRfzHMmSWAcrpg4+/fTTacGCBeX2GOkVZw2MfVc+OMOHD09du3ZN48ePb9CHGCm2ePHi9OSTT5bb4oHeeeed8+09//zz5fYI77bbbrs0derU9PLLL5fbY/5mjDqLMxVOmjQprTPz7dtd2m1AWtxz09R1/qTUedH08vZLemyYL93mvpo6LXknzFvcc3Ba2m1g6j77H6l22cJy+8Lem6e6Ln1Sj5nPpJocnLxtQd+hqb62S1pnxlMNaprff9tUU7ck9Zj1Tt/ra2rTgv7DU+3SOan7nHf6Xtepe1rYd2jqvHhG6jpvYrl9WZfeaVHvIanLwrdSlwX/Lrd3hJrGj+/UZp97Je3peFKTmtSkJjWpSU1qUpOa1KQmNfVotKZSsNWqFzoPt99+ezr55JPTddddl0dFNfc63/ve99Jjjz2Wf4475qyzzkoHHnhgg+0++tGP5lFVRx55ZLNHSg0ePDifwa+0plVbTiar28dNmN9hRhW1x5qO2HGdNvvcq+5jezie1KQmNalJTWpSk5rUpCY1qUlNNY32PWatxSChlS103qKhVIQ/kajdddddaauttmr29WLdqfnz56df/OIX+ecY7fTSSy+l3/72t+VtIqWLlNDZ997h7Httm7PvAQAA0Ba0ibPv3XjjjemQQw5pMpB67bXX0siRI9ODDz6YE7co6kc/+lEeVfWtb32rvN3o0aPT/fffn8aOHZu3e+ONN/LZ+E477bRmB1IAAAAAFKdFQ6kY3XTFFVfkNaGqL2eccUYaNGhQ2n///dOYMWPy/Mf3vOc9ecre3/72t7TZZpuV9xOLnN9zzz3phhtuyNvFdL699torT+kDAAAAoPVp8TWlWhPT92jNTN8DAACgLWgT0/cAAAAA6JiEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQMcKperr69NNN92U9t1337Thhhum9dZbL40aNSq98MILDba7/PLL0+abb5569+6ddt999/TUU08tt6+JEyfm6/bt2zcNGjQonX322amurq7AagAAAABoE6HUrFmz0iWXXJLGjBmTXn311fT666+nD33oQ2mfffZJc+bMydtceeWVaezYsenee+/N25900klpv/32S2+++WZ5P/PmzcvXGTlyZJo2bVqaMGFCeuCBB3IwBQAAAEDrU1Mfw5VaSOmma2pqGrRvs802Oazadddd86inhx56KA0dOrT8+1NPPTV17do1/fjHP84/n3/++enxxx9P119/fXmbt956K22xxRbplVdeSQMHDmxWf2bPnp1HWkX41adPn9TeXP3ovJbuAu/C0bv0bOkuAAAAwBrLV1p0pFSEUdWB1JIlS9L06dNzp++777606aabNgikwmGHHZZuvfXW8s+33HJLOvzwwxtss/7666cRI0akO++8cy1XAQAAAMCq6pxakRg5FaOghg0blnbaaad00UUXpS233HK57YYMGZJeeumlHGB16dIlPffcc01uF79ryqJFi/KlMskLS5cuzZdQW1ubL7E+VeUaVaX2ZcuWlUd8rai9U6dOOYAr7beyPcT2zWnv3Llz3m9le+w3tq/u43Lt9aXr1KRUU5tSfWxbOVCu1N7wNptur40babw9q2tee02nePCb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73+Xp++VpvAtWLBAKAUAAADAuw+lRo8e3ZzNAAAAAGDNhVLh+9//fh4Jteeee6b/+q//anDGPQAAAABYFbXN3fC2225LG220Ubr88svTsGHD0k9+8pO0dOnSVboxAAAAAFilUKpbt27pC1/4Qrr22mvTI488kt588800YsSI9Morr7gnAQAAAFg7oVTlWfb69u2bzj333HTJJZekkSNHpokTJ67arQIAAADQoTU7lIoz8FXbddddczB18MEHpyVLlqzpvgEAAADQ0UOpz33uc422f/SjH0177713eu2119ZkvwAAAABox5p99r3jjz++yd+df/75a6o/AAAAAHQAzR4pBQAAAABrilAKAAAAgMIJpQAAAAAonFAKAAAAgMIJpQAAAAAonFAKAAAAgMJ1bs5G3/jGN1KXLl2a/P3SpUvzpa6uLi1ZsiTtsssu6cgjj1yT/QQAAACgo4VSNTU1qba2NnXt2jV17tw5/7/UHkFUfX19+RI/9+3bd233GwAAAID2Hkqde+65a78nAAAAAHQYzV5T6otf/GKj7TFt77DDDkuzZ89ek/0CAAAAoB1rdih1/fXXL9cW0/WOO+64NGfOnNSnT5813TcAAAAAOnooVVpHquSZZ55Je+21V5o0aVK66aab1kbfAAAAAOjIa0pVjorq169fevbZZ9NTTz2VTj/99HTyySenTp06rd1eAgAAANAxR0rFWff23nvvNHDgwDRjxozUv3//tN122wmkAAAAAFh7oVSXLl3Spz/96fT1r389PfTQQ+mnP/1pOumkk9L3v//9tKasv/76aerUqeWfX3vttdSjR488Oqv6Mnny5AbXnThxYho1alTq27dvGjRoUDr77LNTXV3dGusbAAAAAC0QSi1btqzBz7vvvnt69NFH0/3335/OPPPMd9WJefPmpYsvvjhNmTJluSmDMRJr5syZy10ieKq8/j777JNGjhyZpk2bliZMmJAeeOCBHEwBAAAA0IZDqUMPPXS5tp49e6abb7453XDDDen1119frQ5cdtllab311ssjsFbXz372s7T99tunE044IU8z3GijjdK1116bLrroohxSAQAAANBGQ6mf//znjbb36dMn/fnPf06bbrrpanXgxBNPTPPnz08LFy5Mq+uWW25Jhx9++HJTAUeMGJHuvPPO1d4vAAAAAC189r0VqZxKt6bFulAx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TigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFAAAAQOGEUgAAAAAUTigFwCpZf/3109SpU5v8/aWXXppOOeWUQvsEAAC0PUIpAJpl3rx56eKLL05TpkxpcpsXXnghXXbZZYX2CwAAaJs6t3QHAGj9Img67bTTUl1dXZPbDB48OAdWS5cuTXvssUeh/QMAANoeI6UAWKkTTzwxzZ8/Py1cuLDJbSZOnJh//+1vf7vQvgEAAG2TUAoAAACAwgmlAADagDfffDN97nOfSxtvvHHq169f2m233dLdd9/d0t0CAFhtQikAgDZg//33TwMGDEjPP/98Xr8tptV+8pOfTM8880xLdw0AYLVY6BwAoJV7+eWX00svvZTGjx9fbvvMZz6TbrzxxvTAAw+krbfeukX7BwCwOoyUAgBo5WKEVJxI4NVXXy23zZo1Kz355JNp5513btG+AQCsLiOlAABauVhD6txzz83rSH3lK19JG264Ybr88svT2WefnXbYYYeW7h4AwGoxUgoAoA047LDD8qiosWPHphtuuCGPmnr66afT/PnzW7pr0G4dd9xxqXfv3jkYrryMHj26pbsG0C4YKQXAKqmvr1/h77/73e8W1hfoKO6666784finP/1pOuigg3Lb9OnT0wknnJAOOeSQ9Mc//rGluwjt0pIlS9J3vvOddPrpp7d0VwDaJaEUAEArd9ZZZ6Uf//jH5UCqtM7UVVddlfr375+mTp2a1l133RbtIwDAqjJ9DwCgDaitXf5t26RJk1K3bt1Sr169WqRPAADvhpFSAGvbH85p6R6wuvY/s6V7AFlM0/vyl7+c17bZa6+9ctsDDzyQTjrppDyKqnv37i3dRWi3HnvssTRy5Mj8b8+ePdNHP/rRdP755+fRigC8O0ZKAQC0cp/97GfTJZdcks+2t9FGG6WNN944//+CCy5IX//611u6e9Bubb311nmUYqwrNXny5BwGz5kzJx1wwAErXWMRWD1xbN10001p3333zWebXW+99dKoUaPSCy+80NJdYy2oqffXtGz27Nmpb9++adasWalPnz6pvbn60Xkt3QXehaN36dnSXWB1GSnVdhkpBUCVRYsWpU022SSfgGD77bdv6e5AuzNz5sy8hmKcPGfXXXfNIdVPfvKT9POf/zw9++yzedQw7SdfMVIKAACgmWIdt0033TSPnALWvAgy7r///rT33nvn6ek9evTIo4KjPabR0r5YUwoAAKCZ/vWvf6Xnn38+bbvtti3dFWiXampqlmtbsmRJmj59eruc0dTRCaUAgHbnwslXt3QXeBe+Oujolu4CZKeffnoaNGhQOuqoo9LAgQPT448/no4//vh04okn5tFSwNoX0/dOPfXUNGzYsLTTTju1dHdYw4RSAAAAjTjmmGPSxRdfnHbYYYc8SiOCqFNOOSWf+RJY+2bMmJGPwzjBwC233NLS3WEtEEoBAAA0IqboXXXVVS3dDeiQHn300XTEEUfkkYpnnnlmPhMm7Y9QCgAAAGg1br/99nTyySen6667Lu22224t3R3WIqEUAAAA0CpMmzYtr9t21113pa222qqlu8NaJpQCAADWjF//sqV7wOo69gst3QPIbrzxxnTIIYcIpDoIkzIBAACAVuGll15KV1xxRerVq9dylzPOOKOlu8caZqQUAAAA0CpccMEF+ULH0K5GSk2cODGNGjUq9e3bNw0aNCidffbZqa6urqW7BQAAAEB7DaXmzZuX9tlnnzRy5Mi8MNqECRPSAw88kIMpAAAAAFqXdjN972c/+1nafvvt0wknnJB/3mijjdK1116btthiizR69Og0cODAlu4iAAAArFFP3N3SPWB1bbdPS/eg5bWbkVK33HJLOvzwwxu0rb/++mnEiBHpzjvvbLF+AQAAANCOQ6nnnnsubbnllsu1DxkyJP8OAAAAgNaj3Uzfmzt3burfv/9y7QMGDEhz5sxp9DqLFi3Kl5JZs2blf6dPn56WLl2a/19bW5svsWB65aLppfZly5al+vr6lbZ36tQp1dTUlPdb2R5i++a0d+7cOe+3sj32G9tX97G6fcHc+aXf/CePjG3f6eM77Q1vs+n22v/8rrH2UNfM9k7/6Udj7dV9bKq9/dc0ffqiNvvcq+5jezieVqmmee/8nalN9am2JqVl9TUNHu1OqT7V1KS0tD4e94btue+pee2da+pT3FWV7fG/TjX1qa4+nk0rb49nXW1ur2nwDG6q7+26phkz2vZzrz0eT82saeGcBamm6k95/X/+ZNfUNbP9P3/KG7TX/Gf7ptrrUqqpeDLlp/8K2vM+Ktv/8zLUZHsHqWlWz1lt9rnXHo+nVappwYK32xv50FFf1Z7/Zv/nnU5dM9rz3/IVtMe+65vR3uk/t9GworfbG+t7U+3trqbp09v2c689Hk/NrGn23Nz7VFvTKdXX16X6qmdfY+01qTbV1NQ22V5X3/BZ1nT72zXV1TesKdpDfdWzr6n22pq3a2rY3v5rmj69bT/3VtT3Ug5T2Y92HUr16tUrzZw5M68lVSnaIphqzHnnndfoQujvfe9711o/YXV9saU7AB3SuS3dAeiQvuVVD4p30uiW7gHQDkU41bdv3/YfSsXUvZdeeikNGzasQfuLL76Yjj322Eav841vfCN99atfLf8cqV6MkopF0SPto+2YPXt2Gjx4cJo4cWLq06dPS3cHOgTHHbQMxx4Uz3EHLcOx13bFCKkIpAYNGrTC7dpNKHXAAQekG264IR144IHltqlTp6ZHHnkkXX/99Y1ep1u3bvlSqV+/fmu9r6w98YfKHysoluMOWoZjD4rnuIOW4dhrm1Y0QqrdLXQ+evTodP/996exY8fmEU9vvPFGPhvfaaedlkc+AQAAANB6tJtQKhY5v+eee/JoqRjttPPOO6e99tornXXWWS3dNQAAAADa6/S98L73vS/98Y9/bOlu0AJiGuZ3vvOd5aZjAmuP4w5ahmMPiue4g5bh2Gv/aupXdn4+AAAAAFjD2s30PQAAAADaDqEUAABAIy655JI0Y8aMlu4GQLsllAIAaEeWLl2aFi5cmObOnZuWLVvW0t2BNmXRokUNfj7//PPz8bQqNttss/Tyyy+v4Z5B21RXV9dk+5IlSwrvD62PUIpW7cUXX0yf+9zn0h577JGOPPLI9MADDzT4/W233ZYOOeSQ5f7AXXnlleljH/tYPgvjTjvtlHbYYYe07bbbpqOOOir9/e9/L7gKaHve+973rvIb6nPOOSd997vfbdC2//7755NQbL311vkYHD58ePrABz6Q/3/yySfnbcaMGZO+8Y1vrNH+Q1sTb8y/9KUv5WNv6NCh6Ve/+lVu/7//+7/8Ghb23HPPdO+995avs/vuu+djqvRat/322+fLrrvumvbZZ5+08cYbp8cff7zFaoLW7sADD0x//etfG7TF2bv/9re/lX/u3r17qqmpafT63//+9/PZv6tFGGxRZkjpL3/5S+rTp09+bYrXqQ996ENpt912S7vsskt+7YrXtVURy2H37t07/1spXic/+MEP5tfFD3/4w/k24rYqP1PG6yKtU7s6+x7ty+uvv57/UF122WXpIx/5SHrwwQfTAQcckP7whz/kPzSha9euqUePHg2ud+655+Y/gL/+9a/ToEGDGnxzfNddd6WDDjoojR8/Pm244YaF1wStQbxwz549O3Xu3Lkc5MaIivjwu/7665ffhNfWvvO9xeWXX57++7//O7d36tQpH0+xj1deeSX/HOJNe2mfJf/f//f/5TcOsa8vf/nL+d8LL7ww/y72Ebp06ZIv0JH98Ic/zMfSP//5z3w8fvSjH81v2KOtf//+eZs4vuLNfUm81q1IBMADBgxY632Htipek6ZNm5amTp2aXwsjTIpL5XvL6te1SnEMxgftanHcxntU6Oji/V28lv35z39u9nWeeOKJdN5556VJkyblLzW/9a1vpU033bT8XrN0qfToo482OFbffPPN/JmvJI5H53drvYRStFq/+93v0nHHHZdGjRqVf/74xz+eTjrppHT11VeXQ6lQ+kBcEuHV8ccf3yCQCvGHauTIkflb5WeeeUYoRYcVoWxl4BRvwPv27ZvWXXfdJo+rz3/+8+mLX/xig7bBgwev9AW+8o3DCy+8kHr27Fn+XenNQ/y7ojf90BH8/ve/T/fff38+NiN4ipG99913Xx61Ufnmu6ljZebMmenJJ5/M3xKX/Otf/8qjpYDGxbH17W9/Owe/cezFiMXnnnuuwTYr+tIkXtcqX08rX0ObGl0FHUlTU/dKFi9enI+x0vESo/Q/9alPpd/+9rdp2LBhady4cfl18Omnny6HxY0dk9WvjTfeeGM6+uijG7SZzt56+RRAqxUv8uuss06DtgiUbr/99jzFId68z58/P/3Xf/1Xg20+85nPpDPPPDP/P8Kr9dZbL68FECOvbrrppvTSSy/l4Z3QUVW/gY7pPVtuuWWjb6xLGnsD0Ngb7qZCqtdeey1NmDAhv2l49dVX83obldfx7RUdXRx/c+bMSb169co/T5w4MW2xxRb5/6XjY0Vv7mPUYnybXJqKFPuKN/CmEEHT4kPqz372swZTiOL/la9J8f+YehTHX4wo3mijjXJ7vK+M4/RPf/pTXjKi+nj2ugYpf5aLz2Ex+jeOiQh9Y+BAfEkZx1+0xUCE0hcoP/7xj/OSDqXPavGFaIxIvOGGG9IxxxyT21Y2CjFGP8YXPX/84x8btJdeQ+M2hcati1CKVuvggw9O++67b55+EHODp0yZksaOHZu+9rWvlecE33HHHemaa65pcL1YeyrePMT0vV/84hfp3//+d/4gvMEGG6S99947rxNQetMPpHwMVQ5xbo7SC/qsWbPymhylN+gxSrGxRWPj26ozzjgjh1Gf+MQn8lTa0lTBeFNSPTILOpqvfOUreY3EU045JU/hi9e3eCMeH3pLH25X9CE3jqHK4yg+CDz00EOF9B3aqqYWWS5NLy/9P9YjLYVRJbF+aXxgjg/UP/jBDxp8UI7Xx5WNEIGOID6TVa7RFp/tvv71rze5llQMOigNLqi8TnyxWQqlVvSecd68eWn06NH5M2P1F6oxU2DHHXfM7Q8//PC7rIw1SShFqxWLvd5yyy05MT/77LPzVKGzzjqrwdS9eMEvvXEo/T/eFGy11VbpRz/60UrfiFjHho7urbfeykOjY9pPpepviX/zm9+k008/PR+HcdzEt8ARKsVikxEAR9ull1663IfmCIUPP/zwvBbAV7/61fxGPdbuiG/AYoHYCJHj2PWNMh3dEUcckTbffPP06U9/On32s5/NgVJ8kxyhVLyhj9/FdLwQo6FiOnuMhIovXeJ4jCkQkydPbrC+TRxb0R7HbfU3xsDbX4rElyZxrMXrU/wcx1xlKBVt1QFTLJocr4vxITfWgIv3nDENsCSOyTihR/wbH7Lf//73F1oXtLRY4ynCofhcVlpjLY6HZ599Nn3zm9/M6x3GcbZgwYI8kiq+wIzXtnhfWrmcRIiBBTH6qVr1l5oxnTa+aL3ooovKX3xW2mabbXK/aH2EUrRqES5F0h3iDUGsmVESf7zim+D4gxcee+yxvAZH/NGL6QqlP4Kl68YfrtJpskuBVKwtBR1ZnAHvxBNPbHSNtTjrZbyBiFC4NDX24osvXm67mPoXYl2qyvn6MVU2znwSZ9CMRZxLQ6VPOOGE3F765qyxN/zQEY0YMSKfrTJGH5bWX4vANs5SFB9sY12NEKOHn3rqqRbuLbR9d95553KLJsfrUeV09gh2K1/bYqpsnHgnPvjGh+Xzzz8/L+QcCzJ/8pOfLO8j1sBp7IMxdATxBUmcNX1V1wwtBVCVIxNnzJiR2ytHQ8VnxDjOnn/++fyZMM5MG58L40zQTVnRMhW0LKEUrf7NQozCuO666/I3UXGa7EjQQ4zsiA/UpWApRl7EN1dA88T6M2+88UYeKVUtPgjHh+DS2k9xHDY2XDrWrYkPzPG7mGIbAVdJrIcT30jFPuKNQ+X1Y324uITDDjvMWYro8OKYi5GF06dPz2etjDfYMY3v2GOPLYe2zVkDI/YT25dGIDq2IK3wQ2ocZ/HhuTQ1qPqDa3yRWQql4mQ6Mfo3RkUdeuihuS0+PMf6NREmx4jG7bbbLm9vzRo6sjiOSsdXHDPxHjAGBERIFf8vvVbFkiqxXnBJrBUc67RVLlJ+zz33NFi3LV7XYsRVSQxG2G+//Va4kHmsY3XttdeulVp594RStGrxRyfW1Yj5yKFyLaiYWxxTFaqn4Y0ZMyYP3YxpRaU1NirfpMf0h/iwHWtVQUcU4VGsW/OPf/wjv9A3dxpraUHK+MYqTtMbC6THtLzSmYpiOl71+hwxDTdC5Vh3Y5NNNslvRuL2SiMX49/oTwTMMdUBOqIY5RsLKMeb5ni9izfyMXoxRk6VjpfG1qmJN+1xHEZ76QNAvOaVpvTFlzaVI4yB5cXrWZzpqxRKVYspeqXRxEOGDMlLS1ROkw3xc3wxGu89QxynQilIOaiN6eiNvdeML2Iql2UJsdRDBEzxerjrrrvmNUjjGLzsssvK28TIqMbEmaJj/beBAwfm18DSMRjvXWOaYLxHjZk1tD5CKVq1+GOy//7755ApRkqVgqR4g3799denL3zhC/mNREwPqhxmHXOV40N3Y2K0FXRUsRh5TDOIKQbxzXD1GS5Lqtd4ig+6cazFCI6Y6x9r1ETg1Jx1MuKNSCzg/Ktf/arR35977rlO00uHFsdWU+LNeGUoVbnWzdVXX73C/fbr128N9hLap5WdaKN0VrAQ4VRj091DKZAKpqXD22bPnp0XF4+QKb4wKb2/jIEHsaRKvJ+sFO8r43PfeeedlxdE32GHHfKaiJXTAOOzXmMirLrwwgvLJ8SqFGd+/tSnPrXG62PNEErRqkWiXRpGXRpVEb73ve/l+fwx+iL+0MUlhkuH5iyYbFFlOqoY2RRTXyvn5jd3JEdcVufYKo2wakr1B20gNXjzXXodjA+5TX1D3BgjNaB5HnnkkTxKsTTqsHTynDj+4oNzjMCoPiPYipROMgAdXRxPMWI31hltrhghVTmlr7H3lY2dsGpl7yWtKdV6CaVo1eIF/bbbbsuL2ZXemP/iF7/IQy9jxEb8HKMvYqRFnJK39AcpphHFMM/SVIbqpNyoDDqy5gRSqxvcNna9eHN+88035zf9pZMQxHbx4TqO61gnLgJmoPE356WTAsTUoTjjXnN5rYOVizVsZs2atUY/sB5//PHlkxVARxafy+L42nPPPfN7v9KXJZUnoIr3iDHNr7liP42FUrHv4447Lp94J95vVn4xE+85o43WqabekBFasco/XiXxRyw+yDb1xvyJJ57IUxbe8573NPr7WIwyzlwU842BtXu8hli3Ks4U9uUvf7nR68RaOvHGIk7VC6w5P/jBD/IJDQCgpcRnt8o1nqp/t7IptNVi/bcrrrgide/evUF7rBtVWk+4qdujdRJKAQAAAFA4EysBAAAAKJxQCgAAAIDCCaUAAAAAKJxQCgAAAIDCCaUAgFbv8ccfT3fccccqX29Nns+lsX3FmYNWpjnbNEddXV2z+1UyY8aM1NJa8zl1WnPfAKAjEEoBAIW55ZZb0t57773K13vkkUfStddeu8rX++Y3v5nOOOOM9G49+OCDaZdddlmu/f/9v/+Xhg4dmj7wgQ/ky/rrr58v2267bdpuu+3S+9///vS1r31tlW5r4403Tv/6178abX/++eeXa3/ve9+bpkyZ0ui+RowYkV588cVm3e4TTzyRZs+enda07bffPt1///1pbZkzZ04688wz8+MzfPjwfL8PGzYsPwZf/vKX01tvvdXo9RYvXpwfs7heXOeZZ55p8Pujjz46/fKXv1xr/QYAUurc0h0AANqPuXPnpu9+97s5hFhvvfXSaaedlj7ykY+Uf9+tW7dUW1vb7FEsNTU15et16tSpwe9POumkdNNNN+X9LV26NF9i+xiZdPjhh6crr7wyde3adaUjlSLQuPHGG1Pnzp3zaKTSZdCgQem+++7L28R+4lLt5ptvLv8/bj8CmHXXXTf9+c9/TqsjwqWpU6emjTbaaLnfRf09evRYrj36teeee6bu3bunLl265PsjApclS5ak1157Lbc3x1e+8pX0jW98I330ox9dpT7ffffd6b//+79zv/faa6901llnpV69ejXoX/VjF2HR//zP/+R6or/xGJVGgsXjHj/H/Rmh0L777rvC2z/ssMNyMHj77benDTbYoNw+c+bMdMUVV6SPf/zjeaRdyYIFC/LjE8+pn/zkJ/l24/Zef/319PLLL6d99tkn9yt+39z7DgBYPUIpAGCNOfLII/Pok7vuuis99dRT6TOf+UwOH3baaadyQFE9DS2Cg9NPPz0HMREMRaASAcfJJ5+cfvCDH+RtImypdumll+ZLGDduXLrnnnvSVVdd1WCbuL0IIVbk7LPPTuecc85yI6O+973vlX+OflUHK5Ui1DjllFPS1ltvnSZNmpT7HaO0SqHaqowki/ofe+yxtPPOO+f7KkKb0r+N9SHaI2SJEVqV4joxcqi5fYgQprH7eUUeffTR/Dhdf/31aZNNNsmB5FFHHZXrKGnsMb/ooovSxRdfXP756quvTmPGjElvvPFGvi8jUIv7oWfPnivtw0MPPZR++9vfpoEDBzZo79evXx4lF4HZrFmzUt++fXP7woUL0wMPPJCDp7g/4/4r3d6iRYvy6LIIo+J+W9FjDgC8e6bvAQBrREz/+uc//5lDnv79+6fdd989fec730nnnXdeeZsIParX8Ym2Qw45JE8ze/bZZ9NLL72UQ6oIgkpWFg7EiKAIIapV7qMpjY3c+utf/5p22223Brff2L5iNE8EcB/+8IdzqHHNNdfkEO7OO+/MbTGSqrnrOkV4dv7556cDDjgg/ehHP8ptv/jFL9IOO+yQg76Y0tfYGkgRqDRWQ6kt+tgczR3BVike2+9///t5hFiMjIuRR/E8ePLJJ1f4mFcHZTHiLabh/e///m8OsSKMiudQY6PTqn3pS1/Ko7tuuOGGfB/F/RH7Gj9+fDr++OPz41gKpELs99xzz80jqP7xj3/kkV4xkup973tfvt8PPvjgPKUvHrtVDRUBgFVjpBQAsEY8/PDDOYip9LGPfSyPnimJD/nVAUVTYUhlCLSywOS2225rNJRanaAlRstcdtll6Y9//GODflcHYxF+RPAWI24iiCtNe4sRS3/5y1/ydLIIOSKgiqmEK/P5z38+Bygx+itGOEVNJ5xwQr6EGInU2GLnG264Ydp1113zSKfS9MioIS4RlDVX7HtFC3/HCKa4Hyrv03jML7/88gaPWUzhi5FeUUNTj3mlWCssps39/ve/T5/97GfzelBbbLFFs/sdo9z233//dN1116Wf/exneZRd79698z4++clP5pCpWozIit/FCK0PfehD6d///ndeH6xPnz45kCyFXc0N9ACA1SOUAgDWiFgPKUahVIo1fioXmo6AojpYaWrNp8ogY0XhUgRA8+bNSxMnTsxTBmOB63fjpz/9aZ46t9VWWzVorw6lok9/+9vfmtzPgQcemC9RRwREERg1JuqPKXARzMQUxBglFKN0Ro4cmV555ZV06qmnlrdtLNyJqYZrQjxWsU5X1Bl9itvebLPN8uMVAVxMe/vNb36Tg8Z3+5iHCI8itIswKkabxW3FCKYINiPIPPbYY5u8z6rFlLu4NFcsar755puX1zuL/++3337phRdeyG1Ra4zcK007BQDWDqEUALBGxAihWGOoUqzlM2DAgPLPjY2aaWo0SmV7U9OoIoz64he/mH7+85/naWOxrtO9995bDpBWdfpVrE8Uo5pizaFK1f2OaWI77rhjWmeddfL0tBghFFPNYnHt6HfcFxFExZS86GOEKxHyNCb6/txzz+URVaU1lGI6XIzYufXWWxtsWxnuRAgTtxfXiduOdZBKo6Ti51h0Pi4RsEQ/YkTTqFGjmqz917/+dYOfY3+Nne2vUtQZAVSM4qp8zN/znvc0ed/F/0888cQcRsWaYzHNLkYolc54F0FQTAmMNb1iraimztYY0yRjHaoQIVqEkhFslUS/YsRU7Dvut7i/IlQLH/zgB/PC5hEGxmi3mDIaj3uEgrHP6HNM/TNSCgDWLqEUALBGxNSzmEoVH+RLU+8i5InwpqR0ZrtKEVLEekARJkV4E6Nypk2blkaPHr3C25s9e3aemhVnX4spYzHCJqbMxTS4WIspwqLGRug0JRZLjxE6EQQ1tmh45b5iUfbJkyc3usZSTA2LaWTNFXXGCKXqNati+lmcvbDkoIMOKoc3pRFi1WsuRZD19a9/Pd+Xpfs27s94TJo76qikOes5xWP+hz/8oTzFsPSYxzS8pu67CHwidIr1pxrrU4xQi8ci+r2ihdfjsS9NzYv7PJ5nES6VHHPMMXnUUwRd1WKNqVj3KvoeC9NvvPHGOdSMqZAlsXB6hFoAwNojlAIA1og489x2222XRy7F2edisekzzzyzwVnWIiSpHil13HHHpS984QvLhTLVo2sqRQgRQdShhx6aF1MPcf0IlD71qU+lI444It144435eisb7RIBTkwbi7DkvvvuS4MGDVpumxiJ01jAFdPXYjRRaS2txuprjuh73F/RjxitE32O/USfIpyJoCbCq3XXXXe50OiCCy7II44iUIk+Vk6HjOvHds0JmKrNnz9/pdtEaPaJT3wiDRkyJK/NFKONIvCpnPbW2H1SWUdTVuVMgE1N71zRSLnoZ0z1jLW7YtpenBGwdJ0IpGKNqbgAAGuPUAoAWGNisekIieIMcjFtL8KpyulXjQUUTZ1ZrzJQqA6EYmRLaR2iSr169cpncIspZKXbW1EoFYFPjK6KaVyx8HVTYh+NhVKxNlEEb6XFsaOW1QmAQvQhRuZEMBbTAkuihhh9FP2LNawiAKoUU9JiPaQIpQYPHtzoyKAViZFVsdh43GZpOmKIheNjAfWoPS6l6YgRBl511VV5m9KUuAjGYnRbBFO33HJLg/1XP+ZxPzZ3Afp4fJoTUDUWBJZCvRWJ6YxxxsSos1LU8ulPfzqPTIt/AYC1QygFAKwxEapceOGFTf6+sel7zRGhSPWC6NWBVEkEEaUz8UUwsaLbi7CjNEJmReIsdo3tJ0KoyiloZ5xxRlpdMVIqQpDqOqOeWDcqamnsbHoR8JRCnliwO6YCropYuymmXTZnZFJp0fNKH//4x/NlRdepvO8iVIv1n2LNqtJ6XKWz+pW2jfugNFos1tyKqXgrUt2n0JwRa3G/xki3HXbYIfenpHT7MZoKAFh7hFIAQGFWd3pbhASNBQ+rE6KsjgiDGht1E/uOtZ3ijHMRrpSmIMbtxnXiMnz48HT//fev9DZi9FGcjS7WQYpRSbGPCL3i/oqw6eqrr07Dhg1rtA/7779/6tGjR94++lmabhi/O/zww3Po1JRVGdkVwdGqrk1V/ZjHou5xm80dLdUcESBV7685z7VYXD5GecUIrxgFFvdbPIaxplhMK40zIAIAa09N/eq8MwQAWA1x1roYmRJTwIoQ6wXFVL6jjjrqXe2nqalgpeBjRQFL5cLva8OKpsM1p39r2913352DuerF49e2p59+Oo+YqzwzIADQugilAAAAAChcy31tBgAAAECHJZQCAAAAoHBCKQAAAAAKJ5QCAAAAoHBCKQAAAAAKJ5QCAAAAoHBCKQAAAAAKJ5QCAAAAoHBCKQAAAAAKJ5QCAAAAIBXt/we/i8LTypGuZgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nutrition_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\", \"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\", \"์„ฑ๋ถ„ ์ •๋ณด ์–‘์‹\", \"์„ฑ๋ถ„ ์„ ๋ช…\", \"์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ\"]].copy()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์„ฑ๋ถ„์ •๋ณด ๊ฐœ์ˆ˜\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=30, ha=\"right\")\n", + "plt.xlabel(\"์ƒํ’ˆ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์„ฑ๋ถ„ ์ •๋ณด ์–‘์‹\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์„ฑ๋ถ„ ์„ ๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ์„ ๋ช… ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"]==\"O\")][\"์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์„ฑ๋ถ„ ๋…ธ์ด์ฆˆ ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์˜์–‘ ์ •๋ณด (์ˆœ์„œ ์œ ์ง€ O)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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+P1+e+GFF6xv377WsmVLa968uQ0cONC+/vrrkPUmTpxo7dq1s/z8fDvxxBPtiy++iPh4zz77rHXr1s0aNmxohxxyiF111VXuOQAAAACkJoJSAIAasWXLFrv33ntt9OjRtmLFCvvuu+/suOOOsz59+ti2bdvcOo888ohNnjzZ3n33Xbf+ZZddZqeddpqtXbs25LHuuusuu+WWW+yhhx5y673//vsuiFVaWpqgvQMAAACwrwhKAQBqhDKaZs6caaeccorVqVPH8vLybMyYMa597ty5VlhY6H5+4okn7KCDDrKMjAwbNGiQnXPOOTZ+/PjA4yxZssRuvfVWe/vtt61Xr16urVWrVjZu3DjLzMxM4B4CAAAA2BcEpQAANcLn87kl2O7du23jxo3WoEEDe++996xt27bWsWPHkHXOO+88e/nllwM/P/roo3b++efbfvvtF7dtBwAAAFDzCEoBAOJC9Z9GjhxpnTp1sh49etiiRYvs0EMPLbde+/btbenSpS6AJR9++KH17t3bZVTp75o1a+aGAb711lsJ2AsAAAAA1SWr2h4JAIAoNm3aZEOGDHG1pKZPn+7atm/fbo0bNy63bpMmTVwAa8eOHdaoUSP78ccfXW0qFUt/6qmnXNDqtddec8P8/vOf/1j37t0TsEcAAAAA9hWZUgCAGjVnzhzr2bOnCx698847LtAk9evXt82bN5dbX20a9levXj33c05OjnXu3NnN5KcsK/181lln2bBhw2zSpElx3x8AAAAA1YOgFACgxrz66qt27rnnuqF3N9xwgytm7tHQPQ3TC6fC5sqGys7Odj8fdthhrhB6OAWqNKsfAAAAgNREUAoAUCM2bNjgsplmzJjhakKFO+mkk1wAKjww9eKLL9rAgQMDP2uY3mOPPeZm6ws2b968iDWpAAAAAKQGglIAgBrx/PPPu4CSMpoi0fC8sWPHulpTq1evtpKSEps6daobpjd69OiQ2fgOPvhgN2RPmVFFRUU2ZcoUt64KpwMAAABITQSlAAA1QhlQDz/8sKsdFb789a9/deso+HT22We7TKqGDRu6GlHKrGrRokXgcTIzM+2VV16xjh072rHHHuuKoz/++OP29ttvu2F+AAAAAFITQSkAqIRmglP2Tt++fd0McM2bN3fDy77++uuQ9SZOnGjt2rWz/Px8O/HEE+2LL74o91grV650f6sA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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AJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAJROKAUAAABA6YRSAAAAAHTtUGrIkCExbdq0Rm2TJ0+Or371q/Hud787+vXrF+9617vi/PPPb7TNkUceGX379o0BAwY0uhx//PElVwAAAABAa3SLdmDu3Llx+eWXx9SpU5f726WXXhr9+/eP2267Ld7xjnfEU089FQcddFDxty9/+cvFv4sXL45vfvObcfLJJ5fedwAAAAA6YCh1ySWXxEknnRS1tbXN/v2ss86Kmpqa+t/f8573xLe+9a248MIL60MpAAAAADqWNp++d/TRR8e8efNiwYIFzf69YSBV8eqrrxZT+QAAAADomNo8lFpVOX0vR081nar38MMPx+jRo2PdddeNTTbZpFhn6vXXX2+zfgIAAADQjqfvrYrf/e53cdxxx8UFF1wQe+yxR337lltuGX//+9+LdaW23XbbYiRVhlb77rtv3H///VFVVdXs/hYuXFhcKmbPnl38u2TJkuKSqquri0tOL2w4xbDSvnTp0qirq1tpe474yn5U9tuwPeX2rWnv1q1bsd+G7bnf3L5pH5drr6tcpyqiqjqiLrdd1sdl7Y1vs+X26ryR5tsLta1rr6qJKO6r5tqb9rGl9s5fU9PnZId67jXpY6c4ntSkJjWpSU1qUpOa1KQmNalJTdFc35tet0OHUosWLYpTTjkl7rrrrrj99tuLEKqhPDtfQxtuuGH88pe/LP597LHHYptttml2v2PHji1GXTX16KOPRp8+fYqfc+TViBEj4vnnn2+0EHvuOy8TJ06MWbNm1bcPHz68OIvghAkTYv78+fXtI0eOLM4ImPtu+OCMGjUqevToEePHj2/Uh+23376o+4knnqhvywd6hx12KG7vmWeeqW/v3bt3bL311sWZCydNmlTfngvEb7HFFjFlypTiLIZrzXzzdpf0HBSL+mwUPeZNjm4Ll40mW9x7/eLS841/Rc3iOcvu/z7DYknPwdFr9rNRvXTZNMsFfYdHbfd+0XvmU1FVBCdvmt9/ZNRVd4+1ZjzZqKZ5A7eKqtrF0XvWsr7XVVXH/IGjonrJnOg1Z1nfa2t6xYL+I6PbohnRY+6L9e1Lu/eNhX1HRPcFr0X3+a/Ut3eFmsaPr+mwz72KznQ8qUlNalKTmtSkJjWpSU1qUpOaejdbU3NLMTWnqq5hfNbGMmHLO3qdddapb8uRTB/+8Idjs802i5/85CfRq1evVu9vu+22i7PPPjvGjBnT6pFSw4YNi+nTp9evWdWRk8mm7dc8Mq/LjCrqjDUdvN1aHfa517SPneF4UpOa1KQmNalJTWpSk5rUpCY1VTXb9zlz5sSgQYOKEGtFa4K3+1DqjDPOKJLCcePGrdK+Xn755dh0003j6aefjo022qhV18lQKhPKld1pHdWVD81t6y7wNhy645uj9wAAAKA9a22+0u6n7/3iF7+Ixx9/fIXb5PpRQ4cOjc985jMxePDgYkjaUUcdVZzZr7WBFAAAAADladeh1BtvvFGMeMqz6TXnpZdeKpK3ww47LM4///xikfM8414GUbkg+jHHHFN6nwEAAADoYKFU05mEa6+9dqM5iS3Zaqut4uc///ka7BkAAAAAq1NllWYAAAAAKI1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAIDSCaUAAAAAKJ1QCgAAAICOE0rV1dXFjBkzVm9vAAAAAOgSVjmUuu+++2LhwoUxZ86c2H333ddMrwAAAADo1FY5lLr44ovjkUceib59+66ZHgEAAADQ6a1SKFVbWxvjx4+PnXbaKaqqqqJ79+5rrmcAAAAAdFqrFEpdc801sf/++0dNTU3xu1AKAAAAgLeiW2s3fPzxx+Pcc8+Nu+++e9mVu7X66gAAAABQr1Wp0jHHHBP/+Mc/4qabbooBAwbUt7/++utxwQUXFGfiW7JkSbEA+oIFC+LjH/94bLPNNq3ZNQAAAABd0EpDqUWLFsWLL74YPXr0iD59+jT6WwZRM2fObLzDbt3qp/cBAAAAwFsKpTKMuvnmm+OOO+6IMWPGxJ///Ofo3bt38bccNfXNb35zZbsAAAAAgLe20Pnee+8dhx9+eJx55pn1bTltDwAAAABW1SqtVP7FL34xdtxxx2LdqF69ehVT+wAAAABgjY2Uqth9993rz8CX4RQAAAAArNGRUunggw+OTTbZpPhZKAUAAABAKaHUNttsU//zvffe+5ZuFAAAAICubZWn7zW08cYbr76eAAAAANBltGqk1B/+8IdYa621ip+rqqrq2ys/N2wbNGhQvOc971n9PQUAAACga4VSv/vd76K6ujpqa2uLy9KlS+OWW26JD33oQ1FXV1e05b952XzzzYVSAAAAALz9UOrnP//5cm077bRTXHXVVa25OgAAAACseih12WWXRa9evaJbtzc3z5FR06dPj3HjxkVNTU2jbQ888MD6qX4AAAAA8JZDqQULFsTChQuLaXuV6XtHHXVUvPLKK/XT9ypT+ObPny+UAgAAAODth1LHH398azYDAAAAgNUXSqXvfOc7xUioPfbYI/7rv/6r0Rn3AAAAAGBVVLd2w5tuuik22GCDuPTSS2OLLbaICy64IJYsWbJKNwYAAAAAqxRK9ezZMz7/+c/H1VdfHQ8++GC8+uqrsfPOO8fzzz/vngQAAABgzYRSDc+y179///je974XF154YYwePTpefPHFVbtVAAAAALq0VodSeQa+pt73vvcVwdTHP/7xWLx48eruGwAAAABdPZQ64ogjmm3/4Ac/GHvttVe88MILq7NfAAAAAHRirT773lFHHdXi384555zV1R8AAAAAuoBWj5QCAAAAgNVFKAUAAABA1w6lhgwZEtOmTVuu/dJLL43hw4dH3759Y7fddosnn3xyuW3yDIAHHHBAcWbAoUOHxllnnRW1tbUl9RwAAACADhdKzZ07N84///yYOnXqcn+77LLLYty4cXHXXXfFrFmz4phjjomPfOQj8eqrrza6/t577x2jR4+O6dOnxyOPPBL33XdfEUwBAAAA0P5U1dXV1bVlBy655JI46aSTilFNCxcuLIKpddZZp/jbggULilFPf/3rX2PkyJH11znhhBOiR48e8cMf/rB+ofVHH300rr322vptXnvttdh0003j+eefj8GDB7eqL7Nnzy5GWmX41a9fv+hsrnxoblt3gbfh0B37tHUXAAAAYLXlK20+Uuroo4+OefPmFQFUU3fffXdstNFGjQKp9KlPfSpuvPHG+t9vuOGGOOigg5abCrjzzjvHrbfeugZ7DwAAAMBb0a01G33961+P7t27t/j3JUuWFJcc7bR48eLYcccd45BDDom36+mnn47NN998ufYRI0bEc889V9xW9mtF2+XfAAAAAOiAoVRVVVVUV1cXU+a6detW/FxpzyAqZwBWLvl7DtFaHd54440YOHDgcu2DBg0qbivXkhowYMAKt5szZ06L+8/pgnlpOLysYciWsta8ZF0NF06vtC9durToy8raa2pqivurst+G7Sm3b0173v+534btud/cvmkfl2uvq1ynKqKqOqIut204e7PS3vg2W26vzhtpvr1Q27r2qpqI4r5qrr1pH1tq7/w1NX1OdqjnXpM+dorjSU1qUpOa1KQmNalJTWpSk5rUFM31vel131Yo9b3vfS/awtprrx0zZ85crj3bsvA+ffo02m6DDTZYbrsMployduzYZhdDz/WpKvted911ixFXuTZVw4XYN9xww+IyceLEYo5kRZ4lMKcOTpgwIebPn1/fnlMQM0DLfTd8cEaNGlWEfePHj2/Uh+233z4WLVoUTzzxRH1bPtA77LBDcXvPPPNMfXvv3r1j6623Ls5cOGnSpPr2DAe32GKLmDJlSkyePDnWmvnm7S7pOSgW9dkoesybHN0Wvl6//eLe6xeXnm/8K2oWLwvzFvUZFkt6Do5es5+N6qXLplku6Ds8arv3i94zn4qqIjh50/z+I6OuunusNaPxWRLnDdwqqmoXR+9Zy/peV1Ud8weOiuolc6LXnGV9r63pFQv6j4xui2ZEj7kv1rcv7d43FvYdEd0XvBbd579S394Vaho/vqbDPvcqOtPxpCY1qUlNalKTmtSkJjWpSU1q6t1sTZVga7UtdP7FL34xLr300uXaM2nLqXqXX375214cPIOmhgud/+EPf4gzzzyzOJteQ/fff38cfvjh8eyzzxa/5x2T2+23336NtvvgBz9YbNfSVMLmRkoNGzasOINfpZaOnEw2bb/mkXldZlRRZ6zp4O3W6rDPvaZ97AzHk5rUpCY1qUlNalKTmtSkJjWpqarZvuestRwktLKFzlsdSmWq1nTUUl71iCOOiFdffTX++Mc/xtvVNJTK6Xnrr79+keblmfQqTjzxxOKOPvfcc4vfc7RTrjH1q1/9qn6bTOkyJXT2vWWcfa9jc/Y9AAAAuuTZ9zIEauipp56KPffcsxhadv3118eakFPozjjjjDjssMPipZdeKtK4a665pri9U045pX67448/Pu65554YN25ckczltnk2vpNOOqnVgRQAAAAA5WnVmlKVUVFHHnlkMWLqH//4Rzz55JNx8sknx7HHHtvquYJvRYZPuf9dd921GP2UU/VuueWWYp5kRS5yfueddxbh1AknnFCsMZX9+sY3vrHG+gUAAABACaFUzh3ca6+94oUXXogZM2YUQVAuZrU6A6mWZhLmiKe8rMhmm20Wf/rTn1ZbXwAAAABoB6FU9+7d49Of/nTx86mnnhr33ntvHH300UXb6aefvga7CAAAAEBn0+o1pZquur7bbrvFQw89VKzllOs+AQAAAMBqD6UOPPDAZhci/+1vfxvXXXdd/Pvf/271jQIAAADQtbV6+t5Pf/rTZtvz1H5//vOfY+jQoauzXwAAAAB0Yq0eKbUiAikAAAAASg+lAAAAAGC1Tt+79dZb45prromamppWLYa+ePHiYnsAAAAAeMuh1HrrrRfve9/7omfPntG9e/cinKquri4uVVVVxTZ1dXVRW1sbS5YsWe4sfQAAAACwyqHUe9/73uICAAAAAKuLNaUAAAAAaH8jpRo644wzolu3bsUlp+xVput9+9vfXnM9BAAAAKBrj5S66KKLikAq5XpSucbUhRdeuKb6BgAAAEAntUojpdZZZ5047bTTGrVdccUVq7tPAAAAAHRyqzRSKs/A11SPHj1WZ38AAAAA6AJWKZTKNaSaWrhw4ersDwAAAABdwCpN35syZUocccQR9b/nYufTpk2L2traqK52Ij8AAAAA1kAode655xaLm2cAlWfdy5FTO++8c7HoOQAAAACskVDqqKOOWpXNAQAAAKBZ5twBAAAAUDqhFAAAAADtc/reBz7wgaipqSkWNM/FzfNS+bm5tnPOOSd23333Nd97AAAAADpvKPWlL30pevbsGT169CgWOs+FzSuX5kKpd73rXWu+5wAAAAB07lDqox/96JrvCQAAAABdhjWlAAAAAGjfodTf//73OPDAA2OjjTaK3r17xzve8Y7Yf//94+67715zPQQAAACg64ZSd911V3zsYx+LMWPGxF//+teYPXt2PP744/G5z30uTjjhhPjjH/+4ZnsKAAAAQNdaUyr9+Mc/jquuuire//7317ets846ccABB8SWW25ZLIY+evToNdVPAAAA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Lscff3yj7S699NIYPnx4se1uu+0WTz75ZJv1GQAAAIAV6xbt3OLFi+Ob3/xmnHzyyS1uc9lll8W4cePirrvuio022iiuu+66+MhHPhKPPPJIrLfeeqX2FwAAAIBOMFJqZRYsWBCnnnpq/PKXv4xNNtkkqqur46CDDopPfOITce6557Z19wAAAADojKHU3XffXYyOGjlyZKP2T33qU3HjjTe2Wb8AAAAA6OCh1MMPPxyjR4+OddddtxgNletMvf7668Xfnn766dh8882Xu86IESPiueeeK6b/AQAAANC+tPs1pbbccsv4+9//Xqwrte2228arr75arC+17777xv333x9vvPFGDBw4cLnrDRo0KOrq6mLu3LnFwujNWbhwYXGpmD17dvHvkiVLikvK6YB5qa2tLS4VlfalS5cWt7Oy9pqamqiqqqrfb8P2lNu3pr1bt27Ffhu2535z+6Z9XK69rnKdqoiq6oi63HZZH5e1N77Nltur80aaby/Utq69qiaiuK+aa2/ax5baO39NTZ+THeq516SPneJ4UpOa1KQmNalJTWpSk5rUpCY1RXN9b3rdDhtKffWrX230+4YbblisH5X/PvbYY7H22mvHzJkzl7tetuWd06dPnxb3PXbs2DjrrLOWa3/00Ufrr5ejs3LU1fPPPx9Tp05t1I+8TJw4MWbNmlXfnmcAHDJkSEyYMCHmz59f357TCzMcy303fHBGjRoVPXr0iPHjxzfqw/bbbx+LFi2KJ554or4tH+gddtihuL1nnnmmvr13796x9dZbx7Rp02LSpEn17f37948tttgipkyZEpMnT461Zr55u0t6DopFfTaKHvMmR7eFb444S4t7r19cer7xr6hZPKe+fVGfYbGk5+DoNfvZqF66oL59Qd/hUdu9X/Se+VRUFcHJm+b3Hxl11d1jrRmNz4A4b+BWUVW7OHrPWtb3uqrqmD9wVFQvmRO95izre21Nr1jQf2R0WzQjesx9sb59afe+sbDviOi+4LXoPv+V+vauUNP48TUd9rlX0ZmOJzWpSU1qUpOa1KQmNalJTWpSU+9ma6oEWytTVdcwPutAtttuuzj77LOLn88888ziTHsN5Siqww8/PJ599tkW99HcSKlhw4bF9OnTo1+/fh0+mWzafs0j87rMqKLOWNPB263VYZ97TfvYGY4nNalJTWpSk5rUpCY1qUlNalJTVbN9nzNnTjGDLUOsSr7SaUKpl19+OTbddNNiPanBgwfH+uuvXyR+2VZx4oknFg/GqpyBL0OpTChXdqd1VFc+NLetu8DbcOiOLY/6AwAAgPaitflKu1/oPNeP+vGPf1wMVcvULUdE5XpSRx99dHHWvZxmd8YZZ8Rhhx0WL730UpHYXXPNNXH99dfHKaec0tbdBwAAAKAjrimVYdP5559fLHKeZ9zLIOq4446LY445pn6bDJ9yuNiuu+5azGPMeY633HJLMZcSAAAAgPanQ07fW1NM36M9M30PAACAjqDTTN8DAAAAoPMRSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQunYfStXV1cX1118f++yzT6y//vqx7rrrxgEHHBD//Oc/i7+/8MIL0bt37xgwYMBylylTprR19wEAAADoiKHUrFmz4sILL4xTTjkl/vWvf8W///3v2GWXXWLvvfeOOXPmFKFVTU1NzJw5c7nL0KFD27r7AAAAAHTEUKp///5xzz33xF577RW9evUqRkWdeuqpRfvDDz/c1t0DAAAA4C3oFu1cVVXVcm2LFy+O119/Pfr169cmfQIAAACgk4+Uaiqn651wwgmxxRZbxPbbb1+01dbWxhlnnBEjR46MwYMHx0477RQ33nhjW3cVAAAAgI46UqqhGTNmxGGHHVasJXXDDTcUbTmdb9ddd41BgwbFX/7yl2L01K233hqHH354XHPNNcUC6S1ZuHBhcamYPXt28e+SJUuKS6quri4uGXzlpaLSvnTp0iIoW1l7rnuVo74q+23YnnL71rR369at2G/D9txvbt+0j8u111WuUxVRVR1Rl9su6+Oy9sa32XJ7dd5I8+2F2ta1V9Vk2thCe9M+ttTe+Wtq+pzsUM+9Jn3sFMeTmtSkJjWpSU1qUpOa1KQmNakpmut70+t2+FDqoYceioMPPjg+85nPFKOi8o5O6623Xtx+++2Ntt1///3j9NNPj0suuWSFodTYsWPjrLPOWq790UcfjT59+hQ/59n+RowYEc8//3xMnTq1fpsNN9ywuEycOLFYjL1i+PDhMWTIkJgwYULMnz+/vj1HceUZAXPfDR+cUaNGRY8ePWL8+PGN+pCjwBYtWhRPPPFEfVs+0DvssENxe88880x9ewZzW2+9dUybNi0mTZpU357rbuWIsjwL4eTJk2OtmW/e7pKeg2JRn42ix7zJ0W3h6/XbL+69fnHp+ca/ombxnPr2RX2GxZKeg6PX7GejeumC+vYFfYdHbfd+0XvmU1FVBCdvmt9/ZNRVd4+1ZjzZqKZ5A7eKqtrF0XvWsr7XVVXH/IGjonrJnOg1Z1nfa2t6xYL+I6PbohnRY+6L9e1Lu/eNhX1HRPcFr0X3+a/Ut3eFmsaPr+mwz72KznQ8qUlNalKTmtSkJjWpSU1qUpOaejdbUyXYWpmquobxWTt18803x7HHHhu//vWvi1FRrb3O2WefvcLF0JsbKTVs2LCYPn16/XpVHTmZbNp+zSPzusyoos5Y08HbrdVhn3tN+9gZjic1qUlNalKTmtSkJjWpSU1qUlNVs33PGW45oy1DrBWtB97uQ6kMiDJ1u+222+Ld7353q6+X607NmzcvLr/88lZfJ0OpTChXdqd1VFc+NLetu8DbcOiOb47eAwAAgPastflKu1/o/De/+U184hOfaDGQeuGFF2L06NFx//33F6lcFv6DH/ygGFV12mmnld5fAAAAAFau3YdSzz33XPzsZz+Ltddee7nL1772tRg6dGiMGTMmTjnllGKO5MYbb1xM2XvggQdik002aevuAwAAANARp++VyfQ92jPT9wAAAOgIOs30PQAAAAA6H6EUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAAAAAKUTSgEAAABQOqEUAKvkoIMOigEDBix36d27d9x3331t3T0AAKCD6NbWHQCgY7n22muXa5s0aVLssssusd1227VJnwAAgI7HSCkA3rYLLrggjjzyyGK0FAAAQGsYKQXA2zJr1qy46qqrYsKECW3dFQAAoAMxUgqAt+WKK66IMWPGxAYbbNDWXQEAADoQI6UAeMuWLl0aF110Ufzud79r664AAAAdjJFSALxlN9xwQ2y88caxzTbbtHVXAACADkYoBcBbdt5558VXvvKVtu4GAADQAQmlAHhLHnrooXj11Vdjv/32a+uuQJeUZ7x8z3ve09bdAAB4y4RSALzlUVInnHBCVFd7KYGy5Tput9xyS1t3AwDgbfFJAoBVNnny5Ljjjjvis5/9bFt3BbqcKVOmxOmnnx4/+tGP2rorAABvi1AKgFW24YYbxtSpU2Pttddu665Al1JXVxeHHXZY/PCHP4whQ4a0dXeg07v//vvjU5/6VKy33nrRr1+/2GWXXeLuu+9u625Bp+a461qEUgAAHUSOjtp8881jzJgxbd0V6BJymvpHPvKRmDRpUkyfPj2++tWvxic+8YmYOHFiW3cNOi3HXdfSra07AADAyj322GNx1VVXxQMPPNDWXYEuI0dnNBwV/PGPfzxuu+22uPXWW4uAGFj9HHddi1AKYE37w7fbuge8VWPOaOseQGH+/Plx+OGHx7hx46J3795t3R3oMpqbpp7HY58+fdqkP9AVOO66FqEUAEA7N378+GLawp577lnftmTJkuJN+oABA2LvvfeO66+/vk37CJ3dtGnT4le/+lU88sgjcfHFF7d1d6BLcNx1fkIpAIB27v3vf3/MmzdvuekNxx13XEyYMKHN+gVdwbve9a54+eWXY+7cudGrV68455xzin+BNcdx13VY6BwAAKAF//znP2P27NmxaNGiePDBB+O3v/1tHHvssW3dLejUHHddh1AKAABgJWpqauI973lP/PSnP41rr722rbsDXYLjrvMTSgEAdEB77LGHqXvQBl566aXo379/W3cDuhTHXecllAIAAGjGfvvtF7///e9jwYIFxckF/vznP8eRRx4ZZ555Zlt3DTotx13XYqFzAACAZpxwwglx4YUXxuc///mora2NkSNHFmcAGz16dFt3DTotx13XIpQCADqdH0+5sq27wNtw4tBD27oLUNh7772LC1Aex13XYvoeAAAAAKUTSgEAAABQOtP3AACA1eN/rmjrHvBWHf75tu4Bb9Hjd7R1D3irtjZL0UgpAAAAAMrXqUKpF198MQ444IDo379/DB06NM4666xitX4AAAAA2pdOE0rNnTu3WKE/TxM5ffr0eOSRR+K+++4rgikAAAAA2pdOE0pddNFFsc0228QXvvCF6NatW2ywwQZx9dVXx3nnnVeEVAAAAAC0H50mlLrhhhvioIMOatQ2ZMiQ2HnnnePWW29ts34BAAAA0IlDqaeffjo233zz5dpHjBhR/A0AAACA9qNbdBJvvPFGDBw4cLn2QYMGxZw5c5q9zsKFC4tLxaxZs4p/X3/99ViyZEnxc3V1dXHJBdMbLppeaV+6dGnU1dWttL2mpiaqqqrq99uwPeX2rWnPqYm534btud/cvmkfm7bPf2Ne5S//ySNz22V9XNbe+DZbbq/+z9+aa0+1rWyv+U8/mmtv2seW2jt/Ta+/vrDDPvea9rEzHE+rVNPcZf/PVEddVFdFLK2ravRo10RdVFVFLKnLx71xe9H3aF17t6q6yLuqYXv+VFNVF7V1+WxaeXs+66qL9qpGz+CW+t6pa5oxo2M/9zrj8dTKmhbMmR9VTf4rr/vPf9lVta1s/89/5Y3aq/6zfUvttRFVDZ5MxdN/Be3FPhq2/+dlqMX2LlLTrD6zOuxzrzMeT6tU0/z5b7Y386Gjrkl78X/2f97p1Laivfi/fAXtue+6VrTX/Oc2Glf0ZntzfW+pvdPV9PrrHfu51xmPp1bWNPuNovdRXVUTdXW1Udfk2ddce1VUR1VVdYvttXWNn2Utt79ZU21d45qyPdU1efa11F5d9WZNjds7f02vv96xn3sr6nslh2nYj04dSq299toxc+bMYi2phrItg6nmjB07ttmF0N/5zneusX7CW/XFtu4AdEnfa+sOQJd0mlc9KN8xx7d1D4BOKMOp/v37d/5QKqfuPffcc7HFFls0ap84cWIcfvjhzV7n61//epx44on1v2eql6OkBg8eXKR9dByzZ8+OYcOGxYsvvhj9+vVr6+5Al+C4g7bh2IPyOe6gbTj2Oq4cIZWB1NChQ1e4XacJpfbdd9+47rrrYr/99qtvmzZtWjz44INx7bXXNnudnj17FpeGBgwYsMb7ypqT/1H5zwrK5biDtuHYg/I57qBtOPY6phWNkOp0C50ff/zxcc8998S4ceOKEU8vvfRScTa+k046qRj5BAAAAED70WlCqVzk/M477yxGS+Vopx122CH23HPPOPPMM9u6awAAAAB01ul7abPNNos//elPbd0N2kBOw/zmN7+53HRMYM1x3EHbcOxB+Rx30DYce51fVd3Kzs8HAAAAAKtZp5m+BwAAAEDHIZQCAABoxoUXXhgzZsxo624AdFpCKQDWmCVLlsSCBQvijTfeiKVLl7Z1dwBghRYuXNjo93POOad4HVsVm2yySUyaNGk19ww6ptra2hbbFy9eXHp/aH+EUrRrEydOjCOOOCJ23333OOSQQ+K+++5r9PebbropPvGJTyz3H9xll10WH/rQh4qzMG6//fax7bbbxlZbbRWf+cxn4u9//3vJVUDHkm8QvvSlL8U73/nOGDlyZPziF78o2h977LHiWEp77LFH3HXXXfXX2W233WLUqFH1x9w222xTXN73vvfF3nvvHe94xzvi0UcfbbOaoKPI425VP8x++9vfjm9961uN2saMGVOcAGbLLbcsXv/y+Hzve99b/HzssccW25xyyinx9a9/fbX2HzqS/fbbL/7yl780asuzdz/wwAP1v/fq1Suqqqqavf53vvOd4uzfTeWXMBZlhoh77703+vXrV7wnzPeHu+yyS+y6666x4447Fu8Z8/3kqsjlsPv27Vv821C+P91pp52K96Pvf//7i9vI22r4mTLfj9I+daqz79G5/Pvf/y7+o7rkkkviAx/4QNx///2x7777xh/+8IfiP5rUo0eP6N27d6Prfe973yv+A/yf//mfGDp0aKMRG7fddlvsv//+MX78+Fh//fVLrwk6gu9///tRU1MT//d//1eMcPrgBz9YvHHItoEDBxbbdOvWrXiTUZHH3Irkh+FBgwat8b5De5ZvmmfPnl0cP5UvUfIYy8B3yJAh9R+Aq6uXfWd46aWXxo9+9KOiPY/BfC3LfTz//PPF7yk/MFf2WfH//X//X/GmPff15S9/ufj3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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nutrition_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\", \"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\", \"์˜์–‘ ์ •๋ณด ์–‘์‹\", \"์˜์–‘ ์„ ๋ช…\", \"์˜์–‘ ๋…ธ์ด์ฆˆ\"]].copy()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(1, 4, 1)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"์ „์ฒด\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์˜์–‘์ •๋ณด ๊ฐœ์ˆ˜\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=30, ha=\"right\")\n", + "plt.xlabel(\"์ƒํ’ˆ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ƒํ’ˆ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 2)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 3)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์˜์–‘ ์ •๋ณด ์–‘์‹\"].value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์ •๋ณด ์ œ๊ณต ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.subplot(1, 4, 4)\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\")][\"์˜์–‘ ์„ ๋ช…\"].value_counts().reindex([\"O\", \"X\"]).plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ์„ ๋ช… ์—ฌ๋ถ€\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()\n", + "\n", + "#####\n", + "plt.figure(figsize=(12, 6))\n", + "bars = nutrition_df[(nutrition_df[\"์ „์ฒด/๊ฐœ๋ณ„\"]==\"๊ฐœ๋ณ„\") & (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"]==\"O\") & (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"]==\"O\")][\"์˜์–‘ ๋…ธ์ด์ฆˆ\"].str.split(', ').explode().value_counts().plot(kind=\"bar\", color=seaborn_color)\n", + "for bar in bars.patches:\n", + " bars.annotate(f\"{bar.get_height()}\",\n", + " (bar.get_x() + bar.get_width()/2., bar.get_height()),\n", + " xytext=(0, 0),\n", + " textcoords=\"offset points\",\n", + " ha=\"center\",\n", + " va=\"bottom\")\n", + "plt.xticks(rotation=0, ha=\"center\")\n", + "plt.xlabel(\"์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์˜์–‘ ๋…ธ์ด์ฆˆ ์œ ํ˜•\")\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\")\n", + "plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", + "\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ์„ฑ๋ถ„ & ์˜์–‘ ์ •๋ณด ๋™์‹œ ์ œ๊ณต" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAZ2dJREFUeJzt3QeUXGX9P/4nEEIIIaGGDiERBESkg5QE6YQu8AVFqnSQIkpHQhFQikiR3hFQQlNKpEpo0gQpQiCE3lsSEkzf//k8/3P3t2W2Jbt3s7uv1zlzdnfm7t17Z+7Mzn3P5/k83aqqqqoSAAAAAJRotjL/GAAAAAAEoRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAQAAAFA6oRQAAAAApRNKAUAXMW3atNSVVFVVtcl6hw0bloYOHZo++eSTVt/e6dOnp652/7fkcfrggw/S2LFjU2c1ZcqU9t4EACiVUAqADuGEE05IF110Ual/85RTTkmbb755Gjdu3Eyt55VXXknHHntsGjRoUFpiiSXSXHPNlWafffbUu3fv/HNcH7e/+OKLqa188803qXv37mmnnXZKXcV3vvOdtOKKK7b6eh999NF8bEyaNKlV1xvH95xzzpnuuuuuGfr9L774ouI2RZDTs2fPdOKJJ6YyxXG90EILpalTpzZ6XMZz4Te/+U2z1vnjH/84rb766qm9RSA522yzpVNPPbVV17vGGmuk+eefP5Xt0EMPTQsssED6/PPPU2cQz4U+ffqk008/vcHwr6uF9ACzKqEUALO8d955J5111lnp97//fausr7mVGXGCdv/99+cQaUb/zhFHHJFWXnnlNHz48BxwXX755emJJ55IL730UvrHP/6R/vSnP6UhQ4akRx55JK266qpp3333bZOTpR49euSvc88990yt59VXX02HHHJIWm655VKvXr3SfPPNl0+ko3IoTgRnJXPMMUfq1q1bq683gqPWuC8rPUYR4MTJdCUPPPBADhb/9re/Vbw9jqP111+/3vURSEVYFb/bGi6++OK87yNGjGh0uQht4m839nfj9niexLLNEeuad955W7S9W265Zdpuu+2aXC6q1P773/+mJ598Mr399ttNbkds94ILLpha0zzzzDNT6/zPf/6TRo4cmV8z33vvvRxIxuXdd9/N+/TWW2+lN954I02c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+5qaebLu8jWrJwubbrppHkIaFTAAQMcglAIA2lxU10SVzk033VTa32yrsJJZTzzWZ5xxRg6mopIJAOgYhFIAAAAAlK75tdIAAAAA0EqEUgAAAACUTigFAAAAQOnabt5pas0SE9P/zjPPPBquAgAAAJ1atC//5ptv8uzLjc2yK5QqQQRSSy65ZHtvBgAAAEBp3n///bTEEks0eLtQqgRRIVU8GH369GnvzQEAAABoM+PGjcvFOUUe0hChVAmKIXsRSAmlAAAAgK6gqRZGGp0DAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAHRQ/fr1S1988UW96y+99NI0YMCANM8886RBgwall19+udbtVVVVadiwYWmLLbZIiyyySFpooYXSdtttl0aOHFlvXbfeemtabbXVUt++fdMSSyyRjjjiiDRhwoQ23S+6BqEUAAAAdDARCp1//vnp888/r3fb5Zdfnq655pr08MMPp7Fjx6aDDz44bbnllunTTz+tXiauv+CCC9LRRx+d3nnnnfTee++lH/7wh2mTTTZJ33zzTfVyf//739OvfvWrHHKNGTMmPfHEEzng2n///UvbVzqvblURj9Kmxo0blxPleNL36dOnvTcHAACADuySSy5JRx11VJo+fXqaNGlSDqYWXHDBfNvEiRPTYostlp588sm0/PLLV//O4Ycfnnr06JHOPvvs/HMRBXTr1q3WuldaaaUcVm200Ub55z322COtuuqq6cgjj6xe5oUXXkhDhgxJH3/8cSn7S+fNQVRKAQAAQAdy0EEHpW+//TYHUHX985//TEsttVStQCrssssu6a677qr+OcKouoHUlClT0ldffVUrRIhhfa+88kqt5R599NG09tprt+Ie0VV1b+8NAAAAAFrHa6+9lpZbbrl61w8cODCNGjUqB09zzDFHvdujciqqqVZYYYW0xhprVF9/zDHHpPXWWy/ttNNOabfddksPPfRQevfdd/PwQJhZKqUAAACgkxg/fnyab7756l0///zz5+CpUoPyr7/+Ojc5j0Drtttuq3VbVEqddtpp6bHHHks33HBDeuCBB/Lyr776apvuB12DUAoAAAA6id69e+eG5HXFdTFcb+655651/TPPPJPWXHPNtPrqq+cqqHnnnbf6tmnTpuXZ+e6+++48hO/222/Ps/Mde+yx6cc//nFueg4zQygFAAAAnUQM3YthenW98cYbeQhfzaF7MbNeDMu77rrr0sknn5xmm612RBBVUR988EGukIqKqcLWW2+d9t5773TzzTe38d7Q2QmlAAAAoJPYcMMNcwBVN5iKYXkxRK/w5Zdf5obpw4cPzz2jGlKpIXp47733agVVMCOEUgAAANBJxPC8k046Ke25557pww8/zEPwbrrppjRs2LB09NFHVy936623ph133DGtuOKKDa5r0KBBafr06Tm8inWFTz75JA/f+9e//pWvh5khlAIAAIBOJMKn6PkUFVB9+/ZNV1xxRa6I6tevX/UyUUl12WWX5R5UdS8x417o1atXeuSRR3Kl1AYbbJDmmWee/HXSpEnp+eefr7U+mBHdqqL9Pm1q3Lhx+YVg7NixqU+fPu29OQAAAADtnoOolAIAAACgdN3L/5MAAAB0atde2d5bAB3XXvumrkKlFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAUDqhFAAAAAClE0oBAAAAULoOE0qdeuqpacyYMRVve++999Iuu+yS5ptvvtSnT5+01VZbpddee63istOmTUtnnXVWGjhwYOrZs2daaaWV0jXXXNPg3x0xYkQaNGhQmnvuudPCCy+cDjzwwDR27NhW2y8AAACArqhDhFIff/xxOvnkkyuGUh9++GFad91100ILLZSeffbZ9OKLL6YVV1wxrbfeemnUqFH1lv/5z3+ebr755nT11Vent99+O51yyinp2GOPTeeee269ZR944IEccO26667pjTfeSMOHD88B2CabbJImTZrUZvsLAAAA0Nl1q6qqqkqzsI8++igdfPDB6a677sohUv/+/WvdHhVSkydPTnfccUet6/fee+/02WefpXvuuaf6uvvuuy/tvPPOaeTIkWnxxRevvv7RRx9NW2yxRQ6ellxyyXxdhE7LLrtsOuqoo9Lhhx9evWxc/4Mf/CCHW7/+9a+btQ/jxo1Lffv2zRVWUckFAADQqV17ZXtvAXRce+2bOrrm5iCzbKXUhAkT0jzzzJPDowikKonQ6bbbbksHHXRQvdtimF2EUFHZVLjkkkvStttuWyuQCoMHD07LLLNMuvbaa6uvizAr1r/PPvvUWnbOOefMgdell17aCnsJAAAA0DXNsqFUr1690ssvv5yrox577LGKyzzxxBOpe/fuaaONNqp329prr51TuZq/G98PGTKk4ro233zz3D+qZvXU+uuvn4OxuqKqavTo0XnoIAAAAAAt1z3Norp161ZvqF5d77zzTurXr18OpipZdNFFc3gUvv7669yTarHFFmtw2b/97W+11t3YsiHWXbfqqhjiV7PnVJStAQAAANABKqWaO8QvZtxrSNwWyxTLFtc1tWxT6y6ur7l8TWeeeWau0iouRZ8qAAAAADpBKBVD/CrNyFeI23r37l29bHFdU8s2te7i+prL13TcccflZl7F5f3332/BXgEAAAB0frPs8L3miOF90Yx82rRpafbZZ691W0wq+PHHH6cBAwZUVzdFx/e4rqFZ/opli3W//vrrDS4bai5ftxl6XAAAAADohJVS6667bpo8eXJuSl7Xc889lyuaBg0aVN2jar311kvDhw+vuK77778/bbjhhtU/R5Pzxx9/PI0fP77isssuu2yDPacAAAAA6MSh1CKLLJK22WabdOmll9a7La7bdttt0xJLLFF93f7775/uvPPO9Omnn9ZaNmbli8bme+65Z/V1sd555503XX/99bWWjRDsmmuuSQcffHCb7BMAAABAV9Chh++F888/P6299trpqKOOSr/4xS/S1KlT08UXX5zuueee9Mwzz9Radvvtt09bbrllGjJkSLrooovyEL0IpA455JB03nnn1ZpJb6655kqXX355+slPfpJ69OiRttpqq/Thhx+mE044IS244IL5dwAAAADogpVSIYKlp556Kr377rtp1VVXzZe33347Pfnkk2mppZaqt/yNN96Yw6nddtstLbPMMum0005LF154YTrggAPqLbv11lvnyqprr702DRw4MAdTyy+/fLr33nvTHHPMUdIeAgAAAHQ+3aqiIzhtaty4calv3755Jr5otg4AANCpXXtle28BdFx77Zu6Sg7S4SulAAAAAOh4hFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDpOkUo9eKLL6Ydd9wxLb744mnuuedO3/ve99JZZ52VJk6cWGu5r776Ku2///6pX79+ebnBgwenJ598ssH1XnHFFXldPXv2TAMHDkznnHNOmj59egl7BAAAANC5dfhQKkKlddZZJy277LLpoYceSiNHjky/+c1v0oUXXph22mmn6uXGjx+fQ6gxY8akhx9+OC+31VZbpc022yw99dRT9dY7dOjQdPrpp6ezzz47vfPOO+nSSy9Nl112WTr88MNL3kMAAACAzqdbVVVVVerAokKqe/fu6S9/+Uut6//xj3+kLbbYIr3//vtpiSWWSMccc0wOrZ555pk022z/L4s75ZRT0rBhw9JLL72UunXrlq975ZVX0qqrrpqeffbZtMoqq1QvO2rUqLTiiiumxx9/PK211lrN3sZx48alvn37prFjx6Y+ffq0yn4DAADMsq69sr23ADquvfZNHV1zc5AOXyn19ddfp/nmm6/e9bPPPnv+GkPvpkyZkq688so8dK9mIBXiuv/+9785aCpcfvnlac0116wVSIXvfOc7aeONN84VUwAAAADMuA4fSkVIdN1116Xbbrut+rr//Oc/ab/99ku77bZbWnDBBXPlU/STGjJkSL3fX3TRRdPKK6+cRowYUX3do48+WnHZENVXNZcFAAAAoOW6pw4uhuW98MILuX9U9JVacsklc4+oI444Ig/NC9ETKobmRQBVSVw/evTo6p9j+cUWW6zBZd9+++022hsAAACArqHDV0pFP6mDDz44/eAHP0hvvvlmHob3v//9Lz3wwAP5EiZMmJDmmWee6iF9dcXwv1imEN9XGhJYLDtt2rR6M/vVNGnSpDx+suYFAAAAgE4SSk2dOjXtsMMOacstt0zrr79+evXVV/PsenfccUfq3bt32nrrrdNNN92UevXqlWffizCpkvidWL4Qy8d1DS0b4Vb0qmrImWeemRt6FZeo3gIAAACgk4RSV1xxRbrvvvtyD6iLLrooz4w311xzpe233z49/PDDabvttku/+93vUv/+/dP06dPTp59+WnE9H330URowYED1z7H8xx9/3KxlKznuuONyh/niEjMAAgAAANBJQqkXX3wxDR48OK2zzjr1boseUhtuuGGubFpppZVyxdLw4cPrLffZZ5+ll156KS9biKqrSsuG+++/v9aylcw555x5ysOaFwAAAAA6SSi13HLL5UCpUs+mKVOmpFtvvTVtuummqUePHmmvvfZKl19+eaqqqqq13GWXXZZn31t33XWrr9t3333Tk08+mWftq2nUqFHpkUceSQceeGAb7hUAAABA59ehQ6kDDjgg9evXLw0aNCjdfvvteda89957L917771po402ymHVWWedlZcdOnRo+vrrr9Puu++eRo4cmZc744wz0jnnnJOuuuqqWutdbbXV0lFHHZW23Xbb9OCDD6ZPPvkkDxPcfPPN0+GHH55vBwAAAGDGdU8dWDQnf+KJJ3LfqBNPPDGNHj06D9v77ne/m3bZZZd0xBFH5B5TYd55580z8x177LF5eN63336bh/1F5VOlkCnCrKWXXjoddthheb3RrPzII49MhxxySDvsKQAAAEDn0q2q7ng2Wl1UbEVPq2h6rr8UAADQ6V17ZXtvAXRce+2bukoO0qGH7wEAAADQMQmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAACidUAoAAACA0gmlAAAAAOh4odS4cePSPvvsk7766qvW2SIAAAAAOr0ZCqVuvfXWNHz48Px9t27d0nXXXZfGjx/f2tsGAAAAQCc1Q6HUCy+8kK666qr8/dxzz52qqqpae7sAAAAA6MRmKJR64okn0gYbbPD/r2C22VL37t1be7sAAAAA6MRaHEp98cUX6ZlnnklbbbVV9XU9evRo7e0CAAAAoBNrcSh13nnnpU033TQNHDiw+ro555yztbcLAAAAgE6se0uH7V144YX5a62VGL4HAAAAQFtUSt19991phx12SOeff35aeeWVa90WM/DFBQAAAACao8kSp6lTp6ZVVlkljRkzJl1xxRVpu+22q7dMBFIHHnhg7i01bdq0NGXKlDR58uQ0adKk/HXjjTdOZ555ZrM2CAAAAIDOr8lQasKECWnixInVXxvSq1ev1Lt374q3Lb300jO3lQAAAAB0rVCqb9++adSoUenmm29OBx10UPrf//6X9tprr3rLRSXUd77znbbaTgAAAAA6kWZ3KP/JT36SllpqqbT11luntdZaK6244oq1bo9hegAAAADQqo3Ow3rrrZeOP/74dMABB9S6vqqqKveeAgAAAIBWD6XCEUcckd5555309NNP17peKAUAAABAm4VSc8wxR9pll13SsGHDalVKGb4HAAAAQJuFUmHddddNjz/+eK3rhFIAAAAAtGkotcIKK6TjjjtulqmUir9/5ZVXptVXXz316tUrLbHEEmmbbbZJjz32WK3lvvrqq7T//vunfv36pbnnnjsNHjw4Pfnkkw2u94orrkjf+973Us+ePdPAgQPTOeeck6ZPn17CHgEAAAB0bjMcSm277bbVP0fj8yWXXDK1hwiJfvazn6VTTz01/epXv8r9ru6///4cUP3lL3+pXm78+PE5hBozZkx6+OGH08iRI9NWW22VNttss/TUU0/VW+/QoUPT6aefns4+++y8zksvvTRddtll6fDDDy95DwEAAAA6n25VUWbUgUVo9Ic//CE988wzuUKqpilTpuQeWOGYY45JDz30UF5uttn+XxZ3yimn5P5YL730UurWrVu+7pVXXkmrrrpqevbZZ9Mqq6xSveyoUaPSiiuumIcurrXWWs3exnHjxqW+ffumsWPHpj59+rTCXgMAAMzCrr2yvbcAOq699k0dXXNzkBmqlJpVTJgwIf32t79NJ554Yr1AKhSBVIRTMbwvhu7VDKRCXPff//63Vo+syy+/PK255pq1Aqnwne98J2288ca5YgoAAACAGdehQ6nhw4fnXla77757o8tF5VP0kxoyZEi92xZddNG08sorpxEjRlRf9+ijj1ZcNmyxxRa1lgUAAACg5bo3Z6H+/funBRZYIH9fDHGr+bXSdTW/Lrfccunaa69Nre3f//53WmaZZdJcc82Vq5uuu+669Pbbb6fFF1887bzzzumII45IPXr0yD2hYlsigKokrh89enT1z7H8Yost1uCy8TcaM2nSpHypWbYGAAAAQAtDqWjuHeFOiBZU0Vy8+BqVSjF87uSTT87XVbrMN998qS188cUXaZ555kmbbrpp/vnoo4/Os+Q9//zz1T2k/vGPf+RhfrHc7LPPXnE9sX2xTCG+b2ib4/pp06aliRMn5ln5KjnzzDNzryoAAAAAZiKUOvLIIxu8LQKaE044IQdTZevevXt6+umnc1+p448/vvr6lVZaKX33u99NP/zhD9ODDz6YevXqlWffi22tFEzFjHw1q6hi+biukrg+1tFQIBWOO+649Mtf/rJWpVR7zU4IAAAA0Cl7ShUhz9SpU1PZllpqqTy0sGYgVVhnnXXS0ksvnaumYpmo6vr0008rruejjz5KAwYMqP45lv/444+btWwlc845Z+4uX/MCAAAAQAsrpWIWupjKLyqTalYaFcPzIvDZZJNN6s1sV8yAF0Po2sKPfvSjdOyxx6ZRo0blmfHqiln3ot9UVE7F9kdj9H322afWMp999ll66aWX0sUXX1x93frrr5+XrRR23X///WnDDTdsk/0BAAAA6CqaFUodcsghuadUDH+Liqj4GkFU0Vtqm222qf4+LsUy8X2I2yoFVjNrrbXWSuutt17ueXX33XdXN1YvZtD75JNP0mabbZa3fa+99srN0Pfee+9ay1122WV59r111123+rp99903rztm7YtAqxDh1yOPPJIef/zxVt8XAAAAgK6kWaHUfvvtl2ZVN9xwQw6mdtppp3TSSSelBRdcMAdS0dMpqqiWX375vNzQoUPT2muvnXbfffe8XFRQ3Xjjjemcc87JQVNNq622WjrqqKPStttum4OsCKZeeOGFdOihh+YALG4HAAAAoI1DqVnZMsssk5599tkcNMUsfNFUfMUVV0y///3v05577lm93LzzzpsrnCKoiuF53377be47FYFUpZDprLPOyj2pDjvssDR69OjcqDwavkfVGAAAAAAzp1tVMcauCV999VUaPHhwWmyxxdLqq6+edthhh7TmmmvO5J/vGiIoi55WY8eO1fQcAADo/K69sr23ADquvfZNXSUHaXajp+jDNHLkyNxrKWa0iyFzK6ywQrr55pure0cBAAAAQHM0O5SKWfdiJr3TTjstz6b30Ucf5ZnsosdS9Gp64403mrsqAAAAALq4ZodS3bt3rzWDXjQU//Wvf537LUUj8DXWWCM99NBDbbWdAAAAAHTVSqnp06fXu753797p6quvTmeeeWbaZptt0ogRI1p7GwEAAADoyrPvTZo0qcHbYla6aIa+0047pZdffjktvPDCrbF9AAAAAHTlSqlp06blSqmpU6c2uMwJJ5yQBg4cmA488MDW2j4AAAAAunIo1aNHj3TrrbfmYXwNrmy22fJQvsUWW6y1tg8AAACArjx8Lxqd77jjjk0ut8IKK6SLL754ZrcLAAAAgE6s2ZVSAAAAANBahFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDpujdnoTPOOCP17t270WWmT5+eL1OnTk3Tpk2r/jp58uR8OeWUU9Lcc8/dWtsNAAAAQGcPpU466aRUVVWVunfvnnr06JG/zjbbbPkSunXrlm+vdCkcdthhQikAAAAAmh9KRaXT7LPP3pxFAQAAAKB1ekoJpAAAAABol0bnY8aMSVdffXWTy5188snp/fffn9ntAgAAAKATa3YoFUHTfvvt1+gy9957bzr99NPT8OHDW2PbAAAAAOjqoVQ0N59zzjkbvP2ZZ55JP/3pT9O2227bZHgFAAAAQNfW7FAq+krVnE2vpiuuuCJtvPHGadVVV00333xza24fAAAAAF09lJoyZUp65ZVX0ldffZU++uijHECtvfba6YADDkg/+clP8rC9nj17tu0WAwAAANDhdW9JKDV9+vT0gx/8oNb1EUo9//zzuUoKAAAAAFo1lMoLd++enn322fThhx+mf/3rX+mmm25Kzz33XLr++uvTd7/73dSrV6+WrA4AAACALqrZw/eiSioanUel1JAhQ9Kpp56a3nzzzXTllVfmcCoqpt5666223VoAAAAAulYoNW3atFwpVVO3bt3SHnvskf7zn/+k+eefPw0aNCiNHj26LbYTAAAAgK5aKTV58uSKty2yyCLp/vvvT8suu2zacsst0/jx41tzGwEAAADoqqFUjx490korrdTg7TG0b9iwYTmQOvPMM1tr+wAAAADoyo3Ol1lmmfT00083usyCCy6YLrvssjRgwIDW2DYAAAAAOqkWzb7XHFtvvXVrrxIAAACArjp8DwAAAABai1AKAAAAgFkvlPr2229neOVVVVUz9fsAAAAAdNGeUuuss04aNWpUi1Y6ffr0NG3atPx1jjnmSBMnTpyZbQQAAACgq4VS++yzT6526tmzZ+rRo0f1ZbbZZsuXbt261aqMqhlKTZ06NU2ePLlt9wAAAACAzhdKHXHEEeVsCQAAAABdhkbnAAAAAJROKAUAAADArDd8r6aRI0em2WefPXXv3j1foqdU9I4q+kfF1wEDBuTm5gAAAAAw06FUzKC3wgor1GpsXlM0OY+Q6pVXXknLL798c1cLAAAAQBfU7FCqqH66+uqrU//+/evdPmXKlLTZZpvlSioAAAAAaJVQqgib1llnnfTd73634RV2b9GIQAAAAAC6oBY1Oo9gqrFKqKLPFAAAAAA0pkUJUoRODfWUyiubbbbc8BwAAAAAWi2UimbmMcNeQ6KvlFAKAAAAgKa0qAFUBFIPPvhgev311ysGVkEoBQAAAECrhVJFldShhx7a6HJRLQUAAAAArRJKRS+p0aNH575SPXv2rO4tFSFUMWxv+vTpackll2zuKgEAAADoolo0fK9///5ttyUAAAAAdBktanQOAAAAAK1BKAUAAABA6YRSAAAAAMyaPaXOOOOM3OA8ZuCLSzQ0r/R9Q7dtvfXWaf3112/7vQEAAACg84RSJ510Ug6X5phjjjzzXnydffbZq2fgi69FAFXp61xzzSWUAgAAAKBlodTEiRNzEAUAAAAApfWUEkgBAAAA0Jo0OgcAAABg1hy+V8mkSZPSG2+8kb799tu08MILp8UXX1xFFQAAAABtUyn1zjvvpP/7v/9Lffr0Sausskr64Q9/mAYOHJh69+6dttlmm/Taa6+1dJUAAAAAdDEtqpSKwGmDDTZI/fr1S+eee25aY401chj15ZdfpldeeSXdeOONaZ111kkjRoxIP/jBD9puqwEAAADo0LpVVVVVNXfhzTffPM0+++zprrvuanCo3gEHHJDeeuut9OCDD7bmdnZo48aNS3379k1jx47NFWYAAACd2rVXtvcWQMe1176pq+Qgza6UmjJlSnrkkUdyRVRjvaOGDh2allpqqTRt2rQcYAEAAADADPeUinQrgqZlllmm0eXmnXfevNz48eObu2oAAAAAuphmh1ILLLBA7h/1/PPPN7rcvffem4OpKNMCAAAAgJkKpbp165b23HPPtM8++6TRo0dXXGb48OHp4IMPzssAAAAAQKvMvnfWWWelbbfdNq2wwgpp8ODBaeWVV05zzTVX+vDDD3MFVfSbGjJkSDr99NNbsloAAAAAupgWhVK9evXKs+rdcsst+RKz8EXvqBiut8oqq6TTTjsth1YAAAAA0GqhVGHXXXfNFwAAAABo055SAAAAANBahFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDpOmUo9dprr6WhQ4emMWPG1LvtvffeS7vsskuab775Up8+fdJWW22Vl69k2rRp6ayzzkoDBw5MPXv2TCuttFK65pprStgDAAAAgM6t04VSEURtu+226ZRTTqkXSn344Ydp3XXXTQsttFB69tln04svvphWXHHFtN5666VRo0bVW9fPf/7zdPPNN6err746vf3223mdxx57bDr33HNL3CMAAACAzqdbVVVVVeokYle22WabNO+886Y///nPOUjq379/9e1RITV58uR0xx131Pq9vffeO3322Wfpnnvuqb7uvvvuSzvvvHMaOXJkWnzxxauvf/TRR9MWW2yR3njjjbTkkks2a7vGjRuX+vbtm8aOHZurswAAADq1a69s7y2AjmuvfVNH19wcpFNVSsWQvalTp6ZTTz213m0ROt12223poIMOqnfbgQcemEOoGNpXuOSSS3LFVc1AKgwePDgts8wy6dprr22jvQAAAADo/DpNKPX3v/893Xjjjemmm25Ks81Wf7eeeOKJ1L1797TRRhvVu23ttdfOCd5jjz1WfV18P2TIkIp/a/PNN08jRoxo5T0AAAAA6Do6RSgVQ+n233//NGzYsDT//PNXXOadd95J/fr1y8FUJYsuumgaPXp0/v7rr7/O/agWW2yxJpcFAAAAoOUqJzQdyDfffJO233779Lvf/S6tuuqqDS43YcKEPONeQ+K2WKZYtriuqWUrmTRpUr7UHEsJAAAAQCeqlNprr73Sj370o7THHns0ulyvXr3qzcZXU9zWu3fv6mWL65patpIzzzwzDwcsLs1tiA4AAADQVXToUOrdd99Nt99+e7rhhhvyjHvFZeWVV863x9f4OfpMxSx80ex82rRpFWft+/jjj9OAAQOqK6GiO3xcV8lHH31UvWwlxx13XO4wX1zef//9VttnAAAAgM6gQw/fi5nx3n777XrXf/DBB2mDDTZI9957b1piiSXSggsumMaPH58mT56cHn300XrNzp977rlc/TRo0KD8c7du3dJ6662Xhg8fnn7605/WW//999+fdttttwa3a84558wXAAAAADphKBVNy6MCqiERSBW3x3C7bbbZJl166aX1Qqm4btttt83LF6JxegwJ/PTTT9PCCy9ca1a+aJq+5557tsk+AQAAAHQFHXr4Xkudf/75uVLqqKOOysHSqFGj0pFHHpnuueeedMEFF9RaNpqnb7nllmnIkCHpqaeeykP5/vrXv6Yf//jH6bzzzstVWgAAAADMmC4VSkXVVARM0YsqZuqLSwz/e/LJJ9NSSy1Vb/kbb7wxh1MxVG+ZZZZJp512WrrwwgvTAQcc0C7bDwAAANBZdKuKLt+0qXHjxuVZ+KLpeTRQBwAA6NSuvbK9twA6rr32TV0lB+lSlVIAAAAAzBqEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUjCLqqqqSsOGDUtbbLFFWmSRRdJCCy2UtttuuzRy5Mhay1166aVpwIABaZ555kmDBg1KL7/8cq3b99tvv3zbvPPOW+ty2GGHlbxHAAAA8P8IpWAWNXbs2HTBBReko48+Or3zzjvpvffeSz/84Q/TJptskr755pu8zOWXX56uueaa9PDDD+flDz744LTlllumTz/9tHo9U6ZMSSeffHIaM2ZMrUusGwAAANqLUApmUX379k2PPvpo2mijjVLPnj3TXHPNlY499th8/bPPPpsmTpyYf77uuutS//7902yzzZZ23XXXtOOOO6ZzzjmnvTcfAAAAGiWUgllUt27d8qWmqHr66quvUp8+fdI///nPtNRSS6Xll1++1jK77LJLuuuuu0reWgAAAGgZoRR0oB5Thx9+eFphhRXSGmuskV577bW03HLL1Vtu4MCBadSoUTnAKkRl1ZAhQ3Jfqqiqij5TEW4BAABAexFKQQfw9ddf5ybnEUTddttt+brx48en+eabr96y888/fw6wJkyYkH/+3ve+l4f2RV+pjz76KD3++OO5J9XWW2+dlwMAAID2IJSCWdwzzzyT1lxzzbT66qunhx56KM+cF3r37p0bltcV18Wwv7nnnjv//Otf/zrdfPPNae21105zzDFHWmKJJXIfqjfffDO9+OKLpe8PAAAABKEUzML+/ve/p5122imHSFHpFBVPhRi6F8P06nrjjTfyEL4IoBoy55xz5n5UUTkFAAAA7UEoBbOoL7/8Mh100EFp+PDhab311qt3+4YbbpgDqLrBVAzvi6F+jfn444/T66+/nr7//e+3+nYDAABAlwmlot/Oueeem9Zff/00zzzz5D47gwYNylUmdUVz5/333z/169cvD28aPHhwevLJJxtc9xVXXJF78vTs2TNXn5xzzjlp+vTpbbxHkNKtt96adtxxx7TiiitWvD2O35NOOintueee6cMPP0zTpk1LN910Uxo2bFg6+uijq5f71a9+lc4777z0+eef52P3+eefz/2kIvCKaikAAABoD50ilDr44IPTnXfemX7xi1/kE+4XXnghV4r8+Mc/ThdffHH1ctEYOkKo6Lnz8MMPp5EjR6atttoqbbbZZumpp56qt96hQ4em008/PZ199tnpnXfeSZdeemm67LLL8gxo0NaiAiqOt+gdVfdyzDHH5GUifIrjPCqp+vbtm0PUqKyK0LUQodWrr76aVltttRza/uxnP0v77LNPPq4BAACgvXSr6gTTb8UJd1Qz1RVVJNdff3169913889xIh+NoqNxdM3ePKecckquLnnppZdyg+jwyiuvpFVXXTU9++yzaZVVVqkVFETlSsxgttZaazVr+8aNG5cDg7Fjx6Y+ffq0wh4DAADMwq69sr23ADquvfZNHV1zc5BOUSlVKZAqro8hS2HKlCnpyiuvzEP3agZSIa7773//m4OmwuWXX55nPKsZSIXvfOc7aeONN84VLAAAAADMmO6pE7vllluqq5mi8in6SQ0ZMqTecosuumhaeeWV04gRI9IGG2yQr3v00UfTzjvvXHG9W2yxRbroootSV3P9MxPaexOgQ9tjrbnbexMAAABmGZ02lDrhhBPSvffemx577LH8c/SEiqF5EUBVEtePHj26+udYfrHFFmtw2bfffrvBvz1p0qR8qVm2BgAAAEAnG75Xdya+7bffPl144YW5T9Taa6+dr58wYUJu8jz77LNX/L2YsS+WKcT3cV1Dy8ZMZxMnTqx4+5lnnpnHThaXJZdcslX2DQAAAKCz6FSh1NNPP52bk3/66afpxRdfTNtuu231bb169cqz70WYVEnMyBezmtVcPq5raNkIt3r27Fnx9uOOOy438you77///kzvGwAAAEBn0mlCqWhMPnjw4LT77rvnIXsDBgyodXv//v3T9OnTc2BVyUcffVTrd2L5jz/+uFnL1jXnnHPm7vI1LwAAAAB0slDq/vvvT7/4xS/SzTffnE477bTUvXv9VlkrrbRSHko3fPjwerd99tln6aWXXkobbrhh9XXrr79+xWWLv1dzWQAAAAC6YCh11FFHpaFDh6YddtihwWV69OiR9tprr1xRVVVVVeu2yy67LM++t+6661Zft++++6Ynn3wyz9pX06hRo9IjjzySDjzwwDbYEwAAAICuocOHUm+99VZ6/fXX0x577JF7PVW6TJ06NS8bwVU0Qo8hfiNHjkzvvfdeOuOMM9I555yTrrrqqlrrXW211XLYFX2pHnzwwfTJJ5+k++67L22++ebp8MMPz7cDAAAAMGPqj3PrYKK/U4ROSyyxRIPLRGVTDLebd9550+OPP56OPfbYPDzv22+/Teuss06+vVLIdNZZZ6Wll146HXbYYWn06NF5Fr0jjzwyHXLIIW28VwAAAACdW7equmPZaHXjxo3L/axiJr6O3PT8+mcmtPcmQIe2x1pzt/cmAACU49or23sLoOPaa9/UVXKQDj98DwAAAICORygFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAAAAQOmEUgAAAACUTigFAB1Qv3790hdffNHg7X/605/SoYceWu/6XXfdNc0777z1LnPNNVd6/PHH23irAQDg/xFKAUAHMmHChHT++eenzz//vMFlRo4cmS655JKKt91yyy1pzJgxtS7//ve/U58+fdLqq6/ehlsOAAC1da/zMwAwi4qg6aijjkrTp09vcJkll1wyB1ZTp05NgwcPbtZ6//jHP6b99tsvV0sBAEBZVEoBQAdx0EEHpW+//TZNnDixwWXef//9fPuJJ57YrHWOHTs23XjjjemQQw5pxS0FAICmCaUAoAu78sor01ZbbZUWXXTR9t4UAAC6GMP3AKCLmjZtWrrooovS7bff3t6bAgBAF6RSCgC6qDvuuCMtvfTSadVVV23vTQEAoAsSSgFAF/WHP/whHXnkke29GQAAdFFCKQDogp555pn06aefpm222aa9NwUAgC5KKAUAXbRK6vDDD0+zzeatAAAA7cM7UQDoYj744IP04IMPpr333ru9NwUAgC7M7HsA0AFVVVU1evvQoUMbvG2JJZZIn3/+eRtsFQAANJ9KKQAAAABKp1IKgBlzz2ntvQXQsW11UntvAQBAu1IpBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAAAAAlE4oBQAAAEDphFIAANAF9OvXL33xxRftvRkAUK37//sWAADobCZMmJCuuOKK9Pnnn7f3pgBALUIpAADopC655JJ01FFHpenTp7f3pgBAPYbvAQBAJ3XQQQelb7/9Nk2cOLG9NwUA6hFKAQAAAFA6oRQAAAAApRNKAQAAAFA6oVQTRowYkQYNGpTmnnvutPDCC6cDDzwwjR07tr03CwAAAKBDE0o14oEHHkhbbbVV2nXXXdMbb7yRhg8fnt577720ySabpEmTJrX35gEAAAB0WEKpBkTo9POf/zydfvrp6eCDD06LL754WnXVVdMdd9yRvvnmm3TBBRe09yYCAAAAdFhCqQbcc8896bPPPkv77LNPrevnnHPOtPfee6dLL7203bYNAAAAoKMTSjXg0UcfTeuvv36aZ5556t22xRZbpNGjR6cPP/ywXbYNAABaqqqqKi244ILtvRkAUE0o1YB33nknLbbYYhVvW3TRRfPXCKYAAAAAaLnuM/A7XcKECRNS//79K94233zzVS/TUD+qmo3Qi9n6xo0blzqy/42vvL9A84wbNy11Kt9ObO8tgI6tg78vqOuij29u702ADu3QRX+SOpX//a+9twA6rnEd/z1CkX9ElW5jhFIN6NWrVxozZkzF24rre/fuXfH2M888M51yyin1rl9yySVbeSuBjuTA9t4AYBZzRntvADALOcE7BaBw8GGps4iJ4vr27dvg7UKpBkSV1Ouvv17xto8++ih/HTBgQMXbjzvuuPTLX/6y+ufp06enr776Ki2wwAKpW7dubbTFdHWRREfw+f7776c+ffq09+YA7cjrAVCT1wSgJq8JlCEqpCKQaqgtUkEo1YBocn7llVem8ePH16uIuv/++9Oyyy7b4J0bM/TFpaZ55523TbcXCvGPxT8XIHg9AGrymgDU5DWBttZYhVRBo/MGbLPNNjlIuv7662tdP3ny5HTNNdekgw8+uN22DQAAAKCjUynVgLnmmitdfvnl6Sc/+Unq0aNH2mqrrdKHH36YTjjhhDyV7iGHHNLemwgAAADQYamUasTWW2+d7rzzznTttdemgQMH5mBq+eWXT/fee2+aY4452nvzoJYYMnryySfXGzoKdD1eD4CavCYANXlNYFbSraqp+fkAAAAAoJWplIISNJX9jh07Nk2YMCF1djETJVA+r0HAjLxu+OwagLYmlIJW8MQTT6SePXumr776qt5t06ZNy8M9X3/99QZ//7e//W3aa6+90qxuzz33zKW+M2rLLbdMhx9+eKtuE9D461Bneg0CWmb06NH5deF///tfi3/3X//6V+revXv64osv2mTbACAIpaCZ/vSnP6X11luv4m2zzTZbmjRpUppvvvnq3Tb77LPnr/HGriFx29xzzz1D2/XXv/41rbXWWql3795p/vnnT5tvvnn68ssvW7yeu+66Kx1wwAFpn332SX/4wx/SN998U2+ZOLGNSQAaM3Xq1AZvm2eeefKslkB5r0Nt/RoEtI+PP/44nXrqqelnP/tZ+vWvf51GjBhRb5mYrCc09L87KpgbqoaK/9lx+wILLNDKWw6UaeLEiWmllVZK2267bYOvJfE8P/DAA0vfNghCKWimqDKIhvcNnQx269YtXyqJk8JVVlklh0aLLLJIWmqppdISSyyRFlpooRzSnHvuudUnji3xl7/8Je27777pmGOOSaNGjUoPPfRQWmONNfI/n5aIf0JRARXh1jbbbJM/WY1/XiNHjqy3bKU3r/HPbP/998/7E2+AY9+OO+64esFWNFNs7MQYaJvXobZ6DQLax3//+9+06qqr5qG3O+20U1p22WXTQQcdlH75y1826/92vH9YbbXVchVVBNKDBw9ODz/8cL3/2cXrCtBxxfP8pptuSvfff3+65ppr6t2+3377pYUXXjh/KA3twdkhNEN8Unj33XfnaqRK4k1bXBoSb+j+/e9/p+WWW67im8UTTzwxffrppy3erltuuSVtuummaccdd8w/x8lmvElticcffzz985//TC+88EL1J6k77LBDWnLJJdOvfvWr/Eb1vPPOy9dHCX/d4XsxJGCDDTbIgdZjjz2W+vfvn955550cSsVwvVh/IU56J0+enPc57lMnwVDO61BbvQYB7eOwww5LZ5xxRq5uLuyyyy5phRVWSD/96U/TkCFD8olofDhUt5/j5Zdfnk444YR08cUX5/cQ8fpw33335f/9UX0dFdch/kfH706ZMiVXSsdQYP+3oWNaeeWV01lnnZWOOOKItPHGG+cPp8JVV12VHnjggfT00083ORoC2opKKWiGYcOG5Tdi0aulKI+P6+JNWpwgRiDTWDPQeCPX2MliXGKZllpwwQXTU089NVMNiuP3481r3X9Ecd2LL76YjjzyyPTRRx/lyx577FFvP+OT1XjDeuONN6bll18+vwmOr/GJzHPPPZdefvnl6mXjPjj99NNztdT6668/w9sMXdHMvA611WsQ0D7if3dUSNXUt2/ftO6666b//Oc/uYL5vffey/+D674uXHHFFenMM89M//d//5eH+0a15E9+8pN8shqBVaF4zYgK6Pg+TlyBjiv6uv7whz9Me++9d35dePfdd3N1ZbweRDU1tBehFDThww8/zMHMhRdemKt/Dj300PTtt9/mN4MRxowfPz49+eSTjYZS0Wcplq170he/E7fF9TNyQhjbFf2jfvGLX6QZFeW6b731Vr3rX3vttfSd73yn3qeilWbQK96w1hQnysWnrDV/9ze/+U3e17jPgHJeh9rqNQhoH5X+d8fzOYbd1/3fXen/dnyAVFcM16v7P7v4GpctttiilfcCKFN8AHXttdeml156Kb+fiErLtddeO7+/gPYklIJGREVCDEGLTxDjzVj0a4ghctEo8Ouvv671It9YhUL4/ve/n6uR4hKfZkZlQ7wpjJ9/97vfzfAJYbz5jPHhf/7zn2fo92PoX/SmOP744/OJb5zcDh8+PB111FF5SE9UPG222WZ5///xj3/U28+NNtooX3fIIYdUz9ATX6NpelRMRblwId7Uxqe78Y8w/ikCbf861NavQUD5opdkvCbE8Puolo6qqHhtiGbFgwYNyq8VMQwvmqDXfV2I/jERbkcfynjex+3x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X1NTMUeAU8yMBdCavAYBADArEkoBAAAAUDo9pQAAAAAonVAKAAAAgNIJpQAAAAAonVAKAAAAgNIJpQAAAAAonVAKAAAAgNIJpQAAAAAonVAKAKALmTp1avX3VVVVtX4GACiTUAoAYBb3+eefp9/+9rdp4403TksuuWSaa6650uyzz56/LrbYYmn99ddPxx13XBo1alST61p++eVTt27d8u/PNttsaeutt6643J/+9Ke83MSJE9tgjwAAUure3hsAAEDDnn322bTZZpvlMGmPPfZIq6++elpkkUVSz5490zfffJO+/PLL9Nxzz6W///3v6Xvf+1668cYb084779zg+p566qkcSHXv3j1Nnjw5B1OV9OjRI98WfwcAoC10q4q6bQAAZklbbrllDpD+9re/5cqlxhx66KHpvvvuS2+99Vat67/++uv8u3PMMUcOmuL76dOnp2nTplV/jcs888xTHUJdf/316ec//3maMmVKm+4fANB1qZQCAJiFRSj07bff5t5PESo1pk+fPhVDpA022CC9+uqrufopAq6olApRKRXLRzAVrrnmmrTXXnvl7yO8aqiKCgCgNQilAABmYWeddVaullp55ZXTnnvumTbffPM0cODA1Lt37/S///0vD997/vnn0x133JFuueWWdN1119Vbx4svvpjDqIZE4XyEU//617/SX//611xJFcP8mqrMAgCYGUIpAIBZ2BprrJHefPPNdPXVV6e77747DR06NE2aNKn69giOot9UBFcvvfRS/r6uIpCKwOnSSy9Nr732Who/fnyuvPr+97+fh/1FH6rHH388Pfnkk3md77zzTh7SBwDQVvSUAgDoYMaMGZO++uqrNPfcc6cFFlig0SqoQvSI2nfffdNVV12Vdthhh1xpFcHUrbfemvbbb7/csyqqsIqhfX/+85/T7rvvXj20DwCgtQmlAABmQREG1XybVncoXVM/1/Wzn/0s95V64YUX6t0W1VXbbLNNev/999Ntt92Wr4seVsV2GMYHALQF3SsBAGZBgwYNyhVQxSUqmGpeikbkxSWCo7qXf/7zn9XrW2WVVfLwvtNOOy2HT9FDKobonXDCCWnkyJF5GF9UR8X1cYmm58EQPgCgregpBQAwC7rpppvyrHuF119/PQ+7i+BotdVWq7XsxhtvnLbbbrv0q1/9qrrCKr4uueSS1cscccQR6euvv06XXHJJ+s1vflN9fTRNP+ecc/JQvZoVUcXMexFKNWd4IABAS3mHAQAwC1pqqaVq/Tx58uTq6+s2M4/KqXnnnTcNGDCgwfVFsPTb3/42X6In1YQJE3I/qgiw4vuYxa9Xr175EhZaaKG02Wabtcm+AQAEoRQAQAfQWF+nCJaKyqamxLJ33XVXbnwe/aWieqqmeeaZJ6200kq5x1Q0QZ9zzjlnetsBACrRUwoAoINrybw10VPquOOOyzPuPffcc3kGvmhqHn2kxo0bl6876qij0u233577WukpBQC0FZVSAAAdQIRGrRFKjRgxIm266aZp1113rXdbVEnFZbnllku9e/dOW2yxRfr888/TIossMsPbDQDQEKEUAEAXCqUOPfTQHEhNmjQpbb311rnReZ8+fXJfqokTJ6YvvvgiV0tdfPHF+XaBFADQVoRSAAAdQAyxi75SlXpLRSjV3GBq++23T//973/zLH5XX311evPNN3OT8wiposn5YostllZeeeX0u9/9rmI1FQBAa+lW1ZKP1gAAmOWcffbZuTn5lltu2d6bAgDQbEIpAAAAAEpn9j0AAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAASieUAgAAAKB0QikAAAAAUtn+P4RcgVV4dNueAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nutrition_df = emart_df[[\"์ „์ฒด/๊ฐœ๋ณ„\", \"์ˆœ์„œ ์œ ์ง€\", \"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\", \"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"]]\n", + "\n", + "both_O = (\n", + " (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"] == \"O\") &\n", + " (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\") &\n", + " (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\")\n", + ")\n", + "\n", + "ingredient_O = (\n", + " (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"] == \"O\") &\n", + " (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\") &\n", + " (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] == \"X\")\n", + ")\n", + "\n", + "nutrition_O = (\n", + " (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"] == \"O\") &\n", + " (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] == \"X\") &\n", + " (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] == \"O\")\n", + ")\n", + "\n", + "both_X = (\n", + " (nutrition_df[\"์ˆœ์„œ ์œ ์ง€\"] == \"O\") &\n", + " (nutrition_df[\"์„ฑ๋ถ„ ์ •๋ณด ์—ฌ๋ถ€\"] == \"X\") &\n", + " (nutrition_df[\"์˜์–‘ ์ •๋ณด ์—ฌ๋ถ€\"] == \"X\")\n", + ")\n", + "\n", + "df = pd.DataFrame({\n", + " \"์œ ํ˜•\": [\"์„ฑ๋ถ„ & ์˜์–‘\", \"์„ฑ๋ถ„\", \"์˜์–‘\", \"X\"],\n", + " \"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\": [\n", + " len(nutrition_df[both_O]),\n", + " len(nutrition_df[ingredient_O]),\n", + " len(nutrition_df[nutrition_O]),\n", + " len(nutrition_df[both_X])\n", + " ]\n", + "})\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "plt.bar(df[\"์œ ํ˜•\"], df[\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\"], color=seaborn_color)\n", + "plt.title(\"์ˆœ์„œ ์œ ์ง€ O, ์ด๋ฏธ์ง€๋ณ„ ์„ฑ๋ถ„/์˜์–‘ ์ •๋ณด ์ œ๊ณต\", fontsize=16)\n", + "plt.xlabel(\"์œ ํ˜•\", fontsize=14)\n", + "plt.ylabel(\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\", fontsize=14)\n", + "plt.xticks(fontsize=12)\n", + "plt.yticks(fontsize=12)\n", + "\n", + "for i, count in enumerate(df[\"์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜\"]):\n", + " plt.text(i, count+5, str(count), ha=\"center\",)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "itsmenlp", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/eda/product_crawling.py b/eda/product_crawling.py new file mode 100644 index 0000000..b5ea035 --- /dev/null +++ b/eda/product_crawling.py @@ -0,0 +1,186 @@ +import re +import json +import time +import pandas as pd +from tqdm import tqdm +from pprint import pprint + +from bs4 import BeautifulSoup + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +from webdriver_manager.chrome import ChromeDriverManager + + +def get_product_urls(mall_category_url, market, category, limit): + """ + ์นดํ…Œ๊ณ ๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ƒํ’ˆ์˜ ์ด๋ฆ„๊ณผ url ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ํ•จ์ˆ˜ + + :param mall_category_url: ๋งˆ์ผ“์˜ ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ ํŽ˜์ด์ง€ (ex. ์ด๋งˆํŠธ๋ชฐ์˜ ๊ณผ์ผ ์นดํ…Œ๊ณ ๋ฆฌ) + :param market: ์ง€์ •ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„ + :return: ์ƒํ’ˆ๋ช…, url, ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ dict + """ + + BASE_URL = "https://shopping.naver.com" + + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + + all_items = [] + + driver.get(mall_category_url) + last_height = driver.execute_script("return document.body.scrollHeight") + while True: + # ํŽ˜์ด์ง€๊ฐ€ ์ „๋ถ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ + try: + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_3m7zfsGIZR"))) + except Exception as e: + print("ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", e) + + # ์‹œ์ž‘ + soup = BeautifulSoup(driver.page_source, "html.parser") + items_list = soup.find_all("li", class_="_3m7zfsGIZR") + for item in items_list: + source = item.find("a", class_=re.compile(".*_3OaphyWXEP.*")) + name_dict = json.loads(source["data-shp-contents-dtl"]) + all_items.append({ + "name": name_dict[0]["value"], + "url": BASE_URL + source["href"], + "market": market, + "category": category + }) + + # ์ค‘๋ณต ์ œ๊ฑฐ ํ›„ ๊ฐœ์ˆ˜ ์„ธ๊ธฐ + all_items = [dict(i) for i in {frozenset(item.items()) for item in all_items}] + if len(all_items) >= limit: break + + # ์Šคํฌ๋กค + driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") + time.sleep(5) + + # ํŽ˜์ด์ง€ ์ตœํ•˜๋‹จ์ธ์ง€ ํ™•์ธ + new_height = driver.execute_script("return document.body.scrollHeight") + if new_height == last_height: + break + last_height = new_height + + driver.quit() + + print("์ƒํ’ˆ ์ด ๊ฐœ์ˆ˜:", len(all_items)) + return all_items + + +def get_product_details(all_items, limit, output_name): + """ + get_product_urls์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋œ dict๋ฅผ ํ†ตํ•ด ์ƒํ’ˆ์˜ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ํ•จ์ˆ˜ + - ์ธ๋„ค์ผ ์ด๋ฏธ์ง€ ์ฃผ์†Œ + - ๊ฐ€๊ฒฉ(ํ• ์ธ ์ „, ํ›„) + - ๋ณ„์  + - ์ƒํ’ˆ ์ƒ์„ธ ์ด๋ฏธ์ง€ ์ฃผ์†Œ๋“ค + - ์ƒํ’ˆ ์ƒ์„ธ ํ…์ŠคํŠธ๋“ค + - ์ด ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ + + :param all_items: get_product_urls ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜๋œ dict + :param limit: ๊ฐ€์ ธ์˜ฌ ์ƒํ’ˆ์˜ ๊ฐœ์ˆ˜์ด๋ฉฐ, len(all_items)๋ฅผ ์ดˆ๊ณผํ•  ์ˆ˜ ์—†์Œ + :output_name: ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์œผ๋กœ ์ €์žฅํ•  ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฐ ์ด๋ฆ„ + :return: ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์€ dict์— ์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด๊ฐ€ ์ถ”๊ฐ€๋œ dict + """ + + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + + for item in tqdm(all_items[:limit], desc="product meta", total=len(all_items[:limit])): # ์—ฌ๊ธฐ ์ฃผ์„ ํ•ด์ œํ•˜๊ณ  ์•„๋ž˜ line ์ฃผ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ชจ๋“  ์ƒํ’ˆ ๋Œ€์ƒ์œผ๋กœ ์กฐํšŒ ๊ฐ€๋Šฅ + driver.get(item["url"]) + + # ์ƒ์„ธ ์ •๋ณด ํŽ˜์ด์ง€ ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ + try: + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_1Z00EgoxQ9"))) + except Exception as e: + print("ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", e) + + soup = BeautifulSoup(driver.page_source, "html.parser") + + # ์ธ๋„ค์ผ + thumbnail_img = soup.find("div", class_="_2tT_gkmAOr").find("img")["src"] + item["thumbnail"] = thumbnail_img + + # ๊ฐ€๊ฒฉ + items_list = soup.find_all("span", class_="_1LY7DqCnwR") + prices = [int(item.get_text().replace(",", "")) for item in items_list] + if len(prices) > 1: + item["price"] = { + "before_price": max(prices), + "after_price": min(prices) + } + else: + item["price"] = {"before_price": prices[0]} + + # ๋ณ„์  + strong = soup.find("strong", class_="_2pgHN-ntx6") + star = strong.get_text()[2:] + item["star"] = float(star) + + # ์ƒ์„ธ ์ด๋ฏธ์ง€, ํ…์ŠคํŠธ, ์ด ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ + sources = soup.find_all("div", class_="_1Z00EgoxQ9") + imgs = [] + for s in sources: + imgs = [str(i["src"]) for i in s.find_all("img")] # ์ƒ์„ธ ์ด๋ฏธ์ง€ + divs = [divs.get_text() for divs in s.find_all("div", class_="tmpl_tit_para")] # ํ…์ŠคํŠธ - div + texts = [p.get_text() for p in s.find_all(["h2", "p", "strong", "b"])] # ํ…์ŠคํŠธ - h2, p, strong, b (์ˆ˜์ • ๊ฐ€๋Šฅ) + item["imgs"] = {"num": len(imgs), "urls": imgs} + item["texts"] = {"num": len(texts), "divs": divs, "contents": texts} + try: + item["reviews"] = int(soup.find("span", class_="_3HJHJjSrNK").get_text().replace(",", "")) + except Exception as e: + item["reviews"] = 0 + print("passed...", item["url"]) + pprint(item) + print("\n============================================================================================\n") + + driver.quit() + + ##### DataFrame ๋ณ€ํ™˜, csv๋กœ ์ €์žฅ + data_df = pd.DataFrame(columns=["ID", "img-ID", "category", "name", "url", "before_price", "after_price", "star", "thumbnail", "imgs", "texts", "num_reviews"]) + + for idx, item in enumerate(all_items[:2]): + market = item["market"] + + product_df = pd.DataFrame({ + "ID": f"{market}-{str(idx+1)}", + "img-ID": f"{market}-{str(idx+1)}-0", + "category": item["category"], + "name": item["name"], + "url": item["url"], + "before_price": item["price"]["before_price"], + "after_price": item["price"]["after_price"] if "after_price" in item["price"] else None, + "thumbnail": item["thumbnail"], + "star": item["star"], + "texts": [str(item["texts"])], + "num_reviews": item["reviews"] + }) + + image_df = pd.DataFrame(columns=["ID", "img-ID", "imgs"]) + for i, img in enumerate(item["imgs"]["urls"]): + image_df.loc[i] = [f"{market}-{str(idx+1)}", f"{market}-{str(idx+1)}-{str(i+1)}", img] + + product_df = pd.concat([product_df, image_df]) + data_df = pd.concat([data_df, product_df]) + + data_df.to_csv(output_name, index=False) + + return all_items + + +if __name__ == "__main__": + LIMIT = 50 + all_items = get_product_urls(mall_category_url="", market="emart", category="์•„์ด๊ฐ„์‹", limit=LIMIT) + get_product_details(all_items, limit=LIMIT, output_name="./product_details.csv") diff --git a/front/chrome_extension/.gitignore b/front/chrome_extension/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/front/chrome_extension/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/front/chrome_extension/README.md b/front/chrome_extension/README.md new file mode 100644 index 0000000..74872fd --- /dev/null +++ b/front/chrome_extension/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/front/chrome_extension/eslint.config.js b/front/chrome_extension/eslint.config.js new file mode 100644 index 0000000..092408a --- /dev/null +++ b/front/chrome_extension/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/front/chrome_extension/index.html b/front/chrome_extension/index.html new file mode 100644 index 0000000..4425ef0 --- /dev/null +++ b/front/chrome_extension/index.html @@ -0,0 +1,12 @@ + + + + + + Foodly + + +
+ + + diff --git a/front/chrome_extension/package-lock.json b/front/chrome_extension/package-lock.json new file mode 100644 index 0000000..17a9e9a --- /dev/null +++ b/front/chrome_extension/package-lock.json @@ -0,0 +1,3353 @@ +{ + "name": "ai-shopper-chrome", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ai-shopper-chrome", + "version": "0.0.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^7.1.5" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "@types/chrome": "^0.0.293", + "@types/node": "^22.10.5", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.17.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.16", + "globals": "^15.14.0", + "typescript": "~5.6.2", + "typescript-eslint": "^8.18.2", + "vite": "^6.0.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", + "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz", + "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz", + "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.5", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz", + "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", + "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.10.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/chrome": { + "version": "0.0.293", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.293.tgz", + "integrity": "sha512-pghCOLVHsnePWcMEHCxkAfMRx8qJWmj4lUoyF3ZpANniKz8AucIGLSld7smsrTdLUkk/p5JjOCGVDRdUDHx+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", + "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/type-utils": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", + "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", + "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001692", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", + "integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.80", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.80.tgz", + "integrity": "sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", + "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.10.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.18.0", + "@eslint/plugin-kit": "^0.2.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz", + "integrity": "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz", + "integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz", + "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.5.tgz", + "integrity": "sha512-/4f9+up0Qv92D3bB8iN5P1s3oHAepSGa9h5k6tpTFlixTTskJZwKGhJ6vRJ277tLD1zuaZTt95hyGWV1Z37csQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.1.5" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz", + "integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.19.1", + "@typescript-eslint/parser": "8.19.1", + "@typescript-eslint/utils": "8.19.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz", + "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.24.2", + "postcss": "^8.4.49", + "rollup": "^4.23.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/front/chrome_extension/package.json b/front/chrome_extension/package.json new file mode 100644 index 0000000..920fb6c --- /dev/null +++ b/front/chrome_extension/package.json @@ -0,0 +1,32 @@ +{ + "name": "ai-shopper-chrome", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^7.1.5" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "@types/chrome": "^0.0.293", + "@types/node": "^22.10.5", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.17.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.16", + "globals": "^15.14.0", + "typescript": "~5.6.2", + "typescript-eslint": "^8.18.2", + "vite": "^6.0.5" + } +} diff --git a/front/chrome_extension/public/manifest.json b/front/chrome_extension/public/manifest.json new file mode 100644 index 0000000..7a658c1 --- /dev/null +++ b/front/chrome_extension/public/manifest.json @@ -0,0 +1,29 @@ +{ + "name": "AI Shopper", + "version": "0.1", + "description": "๋‚˜์•ผ, ์ž, ์—ฐ์–ด ํ™”์ดํŒ…!", + "manifest_version": 3, + + "permissions": [ + "activeTab", + "scripting" + ], + "host_permissions": [ + "URL/*" + ], + "background": { + "service_worker": "extension/background.js" + }, + + "content_scripts": [ + { + "matches": ["*://smartstore.naver.com/*", + "*://shopping.naver.com/*"], + "js": ["extension/contentScript.js"] + } + ], + + "action": { + "default_popup": "index.html" + } +} \ No newline at end of file diff --git a/front/chrome_extension/src/App.css b/front/chrome_extension/src/App.css new file mode 100644 index 0000000..f3439d1 --- /dev/null +++ b/front/chrome_extension/src/App.css @@ -0,0 +1,7 @@ +#root { + min-width: 720px; + min-height: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} \ No newline at end of file diff --git a/front/chrome_extension/src/App.tsx b/front/chrome_extension/src/App.tsx new file mode 100644 index 0000000..9db7a00 --- /dev/null +++ b/front/chrome_extension/src/App.tsx @@ -0,0 +1,148 @@ +import { useState, useEffect } from 'react'; +import { HashRouter as Router, Routes, Route, Link } from 'react-router-dom'; + +interface IntroduceData { + text: string; + images: string[]; +} + +function HomePage() { + const [introduceData, setIntroduceData] = useState({ + text: '', + images: [] + }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const handleGetData = () => { + setLoading(true); + setError(null); + + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + const activeTab = tabs[0]; + if (activeTab?.id) { + chrome.tabs.sendMessage( + activeTab.id, + { type: 'GET_INTRODUCE_DATA' }, + (response: IntroduceData) => { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError.message); + setError(`์—๋Ÿฌ: ${chrome.runtime.lastError.message}`); + setLoading(false); + return; + } + + if (response) { + setIntroduceData(response); + } else { + setError('contentScript ์‘๋‹ต์ด ์—†์Šต๋‹ˆ๋‹ค.'); + } + setLoading(false); + } + ); + } else { + setError('ํ™œ์„ฑ ํƒญ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + setLoading(false); + } + }); + }; + + useEffect(() => { + handleGetData(); + // eslint-disable-next-line + }, []); + + return ( +
+
+

Foodly Search beta

+
+ + + + {loading &&

๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...

} + {error &&

{error}

} + + {!loading && !error && ( + <> +
+

์ˆ˜์ง‘๋œ ํ…์ŠคํŠธ:

+
{introduceData.text}
+
+ +
+

์ˆ˜์ง‘๋œ ์ด๋ฏธ์ง€ ๋งํฌ:

+ {introduceData.images.length === 0 ? ( +

์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

+ ) : ( +
    + {introduceData.images.map((src, index) => ( +
  • + + {src} + +
  • + ))} +
+ )} +
+ + )} + +
+ ); +} + +function TeamPage() { + const teamMembers = [ + { name: '๊น€์ง„์žฌ', role: 'ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ, MLOps' }, + { name: '๊ณฝํฌ์ค€', role: 'AI ๊ฐœ๋ฐœ' }, + { name: '๊น€์ •์€', role: 'AI ๊ฐœ๋ฐœ' }, + { name: '์˜ค์ˆ˜ํ˜„', role: 'AI ๊ฐœ๋ฐœ' }, + { name: '์œค์„ ์›…', role: 'AI ๊ฐœ๋ฐœ' }, + { name: '์ •๋ฏผ์ง€', role: 'AI ๊ฐœ๋ฐœ' }, + ]; + + return ( +
+
+

์ œ์ž‘์ง„

+
+ +
+ {teamMembers.map((member, idx) => ( +
+

{member.name}

+

{member.role}

+
+ ))} +
+ + +
+ ); +} + +function App() { + return ( + + + } /> + } /> + + + ); +} + +export default App; \ No newline at end of file diff --git a/front/chrome_extension/src/ImageLinkList.tsx b/front/chrome_extension/src/ImageLinkList.tsx new file mode 100644 index 0000000..eac1a19 --- /dev/null +++ b/front/chrome_extension/src/ImageLinkList.tsx @@ -0,0 +1,35 @@ +import React from 'react'; + +interface ImageLinkListProps { + images: string[]; +} + +/** + * ImageLinkList ์ปดํฌ๋„ŒํŠธ + * - images: ์ˆ˜์ง‘๋œ ์ด๋ฏธ์ง€ src ๋ฐฐ์—ด + * - ๊ฐ src๋ฅผ ํ…์ŠคํŠธ ๋งํฌ ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. + */ +const ImageLinkList: React.FC = ({ images }) => { + if (images.length === 0) { + return

์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

; + } + + return ( +
    + {images.map((src, index) => ( +
  • + + {src} + +
  • + ))} +
+ ); +}; + +export default ImageLinkList; \ No newline at end of file diff --git a/front/chrome_extension/src/extension/background.js b/front/chrome_extension/src/extension/background.js new file mode 100644 index 0000000..01daa29 --- /dev/null +++ b/front/chrome_extension/src/extension/background.js @@ -0,0 +1,43 @@ +// background.js + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + const BASE_URL = "http://localhost:8080/" // TODO: ์„œ๋ฒ„ URL ๋ณ€์ˆ˜ํ™” + + if (message.type === 'PRODUCT_INTRODUCE_DATA') { + const { name, images } = message.payload; + + const data = { + link: name, + images: images + }; + + const myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + + const requestOptions = { + method: "POST", + headers: myHeaders, + body: JSON.stringify(data), + redirect: "follow" + }; + + const apiUrl = BASE_URL + "api/image-to-text"; + + fetch(apiUrl, requestOptions) + .then(response => response.json()) + .then(result => { + console.log('API response:', result); + sendResponse({ success: true, data: result }); + }) + .catch(error => { + console.error('API error:', error); + sendResponse({ success: false, error: error.toString() }); + }); + + return true; + } + + if (message.type === "PRODUCT_DATA_TO_SEND") { + console.log('background received:', message.payload); + } +}); \ No newline at end of file diff --git a/front/chrome_extension/src/extension/contentScript.js b/front/chrome_extension/src/extension/contentScript.js new file mode 100644 index 0000000..ed2e1ab --- /dev/null +++ b/front/chrome_extension/src/extension/contentScript.js @@ -0,0 +1,291 @@ +// contentScript.js + +function waitForDetailButton(intervalTime = 500, maxAttempts = 20) { + return new Promise((resolve) => { + let attemptCount = 0; + const intervalId = setInterval(() => { + attemptCount++; + const button = Array.from(document.querySelectorAll('button, a, div')) + .find(el => el.textContent.trim() === '์ƒ์„ธ์ •๋ณด ํŽผ์ณ๋ณด๊ธฐ'); + if (button) { + clearInterval(intervalId); + button.click(); + resolve(true); + } else if (attemptCount >= maxAttempts) { + clearInterval(intervalId); + resolve(false); + } + }, intervalTime); + }); +} + +function findIntroduceDiv(root = document) { + const walker = document.createTreeWalker( + root, + NodeFilter.SHOW_ELEMENT, + { + acceptNode: (node) => { + if (node.id === 'INTRODUCE') { + return NodeFilter.FILTER_ACCEPT; + } + return NodeFilter.FILTER_SKIP; + } + }, + false + ); + + let node = walker.nextNode(); + if (node) return node; + + const shadowHosts = Array.from(root.querySelectorAll('*')).filter(el => el.shadowRoot); + for (const host of shadowHosts) { + const found = findIntroduceDiv(host.shadowRoot); + if (found) return found; + } + + return null; +} + +function findAllImages(root) { + let images = Array.from(root.querySelectorAll('img')); + const shadowRoots = Array.from(root.querySelectorAll('*')).filter(el => el.shadowRoot); + shadowRoots.forEach(el => { + images = images.concat(findAllImages(el.shadowRoot)); + }); + return images; +} + +function waitForIntroduceDiv(timeout = 10000) { + return new Promise((resolve) => { + const introduceDiv = findIntroduceDiv(); + if (introduceDiv) { + resolve(); + return; + } + + const observer = new MutationObserver(() => { + const target = findIntroduceDiv(); + if (target) { + observer.disconnect(); + resolve(); + } + }); + observer.observe(document.body, { childList: true, subtree: true }); + + setTimeout(() => { + observer.disconnect(); + console.warn('INTRODUCE div did not appear within the specified time.'); + resolve(); + }, timeout); + }); +} + +function getIntroduceData() { + const introduceDiv = findIntroduceDiv(); + if (!introduceDiv) { + console.warn('Cannot found [INTRODUCE] div'); + return { + text: '', + images: [] + }; + } + + const introduceText = introduceDiv.innerText.trim(); + const imagesInIntroduce = findAllImages(introduceDiv); + const imageLinks = imagesInIntroduce.map(img => img.src).filter(link => !!link); + + return { + text: introduceText, + images: imageLinks + }; +} + +function createBlackBanner(thumbnailUrl, productName, productPrice, productDesc) { + const banner = document.createElement('div'); + banner.id = 'custom-black-banner'; + banner.style.position = 'fixed'; + banner.style.top = '0'; + banner.style.left = '0'; + banner.style.width = '100%'; + banner.style.backgroundColor = '#000'; + banner.style.color = '#fff'; + banner.style.padding = '15px'; + banner.style.display = 'flex'; + banner.style.flexDirection = 'column'; + banner.style.justifyContent = 'center'; + banner.style.alignItems = 'flex-start'; + banner.style.zIndex = '100000'; + banner.style.boxSizing = 'border-box'; + + const firstLine = document.createElement('div'); + firstLine.style.display = 'flex'; + firstLine.style.width = '100%'; + firstLine.style.alignItems = 'center'; + firstLine.style.marginBottom = '8px'; + + const thumbnail = document.createElement('img'); + thumbnail.src = thumbnailUrl || ''; + thumbnail.alt = '์ œํ’ˆ ์ธ๋„ค์ผ'; + thumbnail.style.width = '60px'; + thumbnail.style.height = '60px'; + thumbnail.style.objectFit = 'cover'; + thumbnail.style.marginRight = '10px'; + + const nameSpan = document.createElement('span'); + nameSpan.textContent = productName || '์ œํ’ˆ๋ช… ์—†์Œ'; + nameSpan.style.fontSize = '16px'; + nameSpan.style.fontWeight = 'bold'; + nameSpan.style.marginRight = '10px'; + + const priceSpan = document.createElement('span'); + priceSpan.textContent = productPrice || '๊ฐ€๊ฒฉ ์ •๋ณด ์—†์Œ'; + priceSpan.style.fontSize = '16px'; + priceSpan.style.color = '#FFEE58'; + priceSpan.style.fontWeight = 'bold'; + + firstLine.appendChild(thumbnail); + firstLine.appendChild(nameSpan); + firstLine.appendChild(priceSpan); + + const secondLine = document.createElement('div'); + secondLine.id = 'custom-black-banner-desc'; + secondLine.style.marginTop = '8px'; + secondLine.style.fontSize = '14px'; + secondLine.style.lineHeight = '1.4'; + secondLine.textContent = productDesc || '์ œํ’ˆ ์„ค๋ช… ์—†์Œ'; + + const closeBtn = document.createElement('button'); + closeBtn.textContent = 'X'; + closeBtn.style.position = 'absolute'; + closeBtn.style.right = '10px'; + closeBtn.style.top = '10px'; + closeBtn.style.background = 'none'; + closeBtn.style.color = '#fff'; + closeBtn.style.border = 'none'; + closeBtn.style.cursor = 'pointer'; + closeBtn.style.fontSize = '16px'; + + closeBtn.addEventListener('click', () => { + banner.remove(); + document.body.style.paddingTop = '0'; + }); + + banner.appendChild(firstLine); + banner.appendChild(secondLine); + banner.appendChild(closeBtn); + + document.body.appendChild(banner); + document.body.style.paddingTop = `${banner.offsetHeight}px`; +} + +function watchForIntroduceTag(callback) { + if (findIntroduceDiv()) { + callback(); + return; + } + + const observer = new MutationObserver((mutations, obs) => { + if (findIntroduceDiv()) { + obs.disconnect(); + callback(); + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); + + setTimeout(() => { + observer.disconnect(); + console.warn('INTRODUCE div did not appear within the specified time.'); + }, 10000); +} + +/** + * ์ˆ˜์ง‘๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด๋‘˜ ์ „์—ญ ๋ณ€์ˆ˜ + * (ํŒ์—…์—์„œ ์š”์ฒญ ์‹œ ์‘๋‹ตํ•˜๊ธฐ ์œ„ํ•ด) + */ +let collectedData = { + text: '', + images: [] +}; + +async function main() { + const buttonClicked = await waitForDetailButton(); + if (buttonClicked) { + console.log('"์ƒ์„ธ์ •๋ณด ํŽผ์ณ๋ณด๊ธฐ" button clicked'); + } else { + console.warn('"์ƒ์„ธ์ •๋ณด ํŽผ์ณ๋ณด๊ธฐ" button not found'); + } + + await waitForIntroduceDiv(); + + const { text, images } = getIntroduceData(); + collectedData.text = text; + collectedData.images = images; + + chrome.runtime.sendMessage({ + type: 'PRODUCT_DATA_TO_SEND', + payload: { text, images } + }); + + // name + let productName = '์ œํ’ˆ๋ช… ์—†์Œ'; + const nameElem = document.querySelector('h3._22kNQuEXmb'); + if (nameElem) { + productName = nameElem.textContent.trim(); + } + + // price + let productPrice = '๊ฐ€๊ฒฉ ์ •๋ณด ์—†์Œ'; + const priceElem = document.querySelector('strong.aICRqgP9zw._2oBq11Xp7s span._1LY7DqCnwR'); + if (priceElem) { + productPrice = `${priceElem.textContent.trim()}์›`; + } + + // thumbnail + let productThumbnail = ''; + const thumbElem = document.querySelector('._2tT_gkmAOr > img._2RYeHZAP_4'); + if (thumbElem) { + productThumbnail = thumbElem.getAttribute('src') || ''; + } + + createBlackBanner(productThumbnail, productName, productPrice, text); + + chrome.runtime.sendMessage({ + type: 'PRODUCT_INTRODUCE_DATA', + payload: { + name: window.location.href, + images: images + } + }, function(response) { + if (chrome.runtime.lastError) { + console.error('background error:', chrome.runtime.lastError); + return; + } + + console.log('background response:', response); + + const newDescription = Array.isArray(response?.data?.texts) + ? response.data.texts.join('\n') + : '์ถ”๊ฐ€ ์„ค๋ช… ์—†์Œ'; + + const bannerDesc = document.getElementById('custom-black-banner-desc'); + if (bannerDesc) { + bannerDesc.textContent = newDescription; + console.log('banner updated'); + } else { + console.warn('cannot find banner description element'); + } + }); +} + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request?.type === 'GET_INTRODUCE_DATA') { + sendResponse(collectedData); + return true; + } +}); + + +(function(){ + watchForIntroduceTag(main); +})(); \ No newline at end of file diff --git a/front/chrome_extension/src/index.css b/front/chrome_extension/src/index.css new file mode 100644 index 0000000..6119ad9 --- /dev/null +++ b/front/chrome_extension/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/front/chrome_extension/src/main.tsx b/front/chrome_extension/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/front/chrome_extension/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/front/chrome_extension/src/vite-env.d.ts b/front/chrome_extension/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/front/chrome_extension/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/front/chrome_extension/tsconfig.app.json b/front/chrome_extension/tsconfig.app.json new file mode 100644 index 0000000..358ca9b --- /dev/null +++ b/front/chrome_extension/tsconfig.app.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/front/chrome_extension/tsconfig.json b/front/chrome_extension/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/front/chrome_extension/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/front/chrome_extension/tsconfig.node.json b/front/chrome_extension/tsconfig.node.json new file mode 100644 index 0000000..db0becc --- /dev/null +++ b/front/chrome_extension/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/front/chrome_extension/vite.config.ts b/front/chrome_extension/vite.config.ts new file mode 100644 index 0000000..fc76236 --- /dev/null +++ b/front/chrome_extension/vite.config.ts @@ -0,0 +1,48 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import { resolve, basename, extname } from 'path' +import fs from 'fs' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], + build: { + rollupOptions: { + input: (() => { + const extensionDir = resolve(__dirname, 'src/extension') + + const entries: Record = {} + + // Process files in src/extension + if (fs.existsSync(extensionDir)) { + const extensionFiles = fs.readdirSync(extensionDir) + + extensionFiles.forEach((file) => { + const name = basename(file, extname(file)) + entries[`extension/${name}`] = resolve(extensionDir, file) + }) + } + + // Add the main entry (e.g., popup or main application) + entries.main = resolve(__dirname, 'index.html') + + console.log('Generated Rollup input entries:', entries) + return entries + })(), + output: { + // Customize the naming convention for the output files + entryFileNames: (chunkInfo) => { + const moduleId = chunkInfo.facadeModuleId + + if (moduleId?.includes('/src/extension/')) { + const fileName = basename(moduleId) + return `extension/${fileName}` + } + + return 'assets/[name].js' + }, + assetFileNames: 'assets/[name].[hash][extname]', + }, + }, + }, +}) diff --git a/front/foodly_application/.bundle/config b/front/foodly_application/.bundle/config new file mode 100644 index 0000000..848943b --- /dev/null +++ b/front/foodly_application/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/front/foodly_application/.eslintrc.js b/front/foodly_application/.eslintrc.js new file mode 100644 index 0000000..187894b --- /dev/null +++ b/front/foodly_application/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: '@react-native', +}; diff --git a/front/foodly_application/.gitignore b/front/foodly_application/.gitignore new file mode 100644 index 0000000..604286c --- /dev/null +++ b/front/foodly_application/.gitignore @@ -0,0 +1,78 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +**/.xcode.env.local + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +**/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* + +# testing +/coverage + +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# env +env +.env diff --git a/front/foodly_application/.prettierrc.js b/front/foodly_application/.prettierrc.js new file mode 100644 index 0000000..2b54074 --- /dev/null +++ b/front/foodly_application/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + arrowParens: 'avoid', + bracketSameLine: true, + bracketSpacing: false, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/front/foodly_application/.watchmanconfig b/front/foodly_application/.watchmanconfig new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/front/foodly_application/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/front/foodly_application/Gemfile b/front/foodly_application/Gemfile new file mode 100644 index 0000000..03278dd --- /dev/null +++ b/front/foodly_application/Gemfile @@ -0,0 +1,10 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby ">= 2.6.10" + +# Exclude problematic versions of cocoapods and activesupport that causes build failures. +gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' +gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' +gem 'xcodeproj', '< 1.26.0' +gem 'concurrent-ruby', '< 1.3.4' diff --git a/front/foodly_application/Gemfile.lock b/front/foodly_application/Gemfile.lock new file mode 100644 index 0000000..d47b6b8 --- /dev/null +++ b/front/foodly_application/Gemfile.lock @@ -0,0 +1,107 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.7) + base64 + nkf + rexml + activesupport (6.1.7.10) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + base64 (0.2.0) + claide (1.1.0) + cocoapods (1.15.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.15.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.3.3) + escape (0.0.4) + ethon (0.16.0) + ffi (>= 1.15.0) + ffi (1.17.1) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.8.3) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + json (2.7.6) + minitest (5.25.4) + molinillo (0.8.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + nkf (0.2.0) + public_suffix (4.0.7) + rexml (3.4.0) + ruby-macho (2.5.1) + typhoeus (1.4.1) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + xcodeproj (1.25.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (>= 3.3.6, < 4.0) + zeitwerk (2.6.18) + +PLATFORMS + ruby + +DEPENDENCIES + activesupport (>= 6.1.7.5, != 7.1.0) + cocoapods (>= 1.13, != 1.15.1, != 1.15.0) + concurrent-ruby (< 1.3.4) + xcodeproj (< 1.26.0) + +RUBY VERSION + ruby 2.6.10p210 + +BUNDLED WITH + 1.17.2 diff --git a/front/foodly_application/README.md b/front/foodly_application/README.md new file mode 100644 index 0000000..3e2c3f8 --- /dev/null +++ b/front/foodly_application/README.md @@ -0,0 +1,97 @@ +This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). + +# Getting Started + +> **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding. + +## Step 1: Start Metro + +First, you will need to run **Metro**, the JavaScript build tool for React Native. + +To start the Metro dev server, run the following command from the root of your React Native project: + +```sh +# Using npm +npm start + +# OR using Yarn +yarn start +``` + +## Step 2: Build and run your app + +With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app: + +### Android + +```sh +# Using npm +npm run android + +# OR using Yarn +yarn android +``` + +### iOS + +For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps). + +The first time you create a new project, run the Ruby bundler to install CocoaPods itself: + +```sh +bundle install +``` + +Then, and every time you update your native dependencies, run: + +```sh +bundle exec pod install +``` + +For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html). + +```sh +# Using npm +npm run ios + +# OR using Yarn +yarn ios +``` + +If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device. + +This is one way to run your app โ€” you can also build it directly from Android Studio or Xcode. + +## Step 3: Modify your app + +Now that you have successfully run the app, let's make changes! + +Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes โ€”ย this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh). + +When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload: + +- **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd โŒ˜ + M (macOS). +- **iOS**: Press R in iOS Simulator. + +## Congratulations! :tada: + +You've successfully run and modified your React Native App. :partying_face: + +### Now what? + +- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). +- If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started). + +# Troubleshooting + +If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. + +# Learn More + +To learn more about React Native, take a look at the following resources: + +- [React Native Website](https://reactnative.dev) - learn more about React Native. +- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. +- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. +- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. +- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. diff --git a/front/foodly_application/android/app/build.gradle b/front/foodly_application/android/app/build.gradle new file mode 100644 index 0000000..99c9227 --- /dev/null +++ b/front/foodly_application/android/app/build.gradle @@ -0,0 +1,142 @@ +apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" +apply plugin: "com.facebook.react" + +project.ext.envConfigFiles = [ + localbuild: ".env", +] + +apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '../..' + // root = file("../../") + // The folder where the react-native NPM package is. Default is ../../node_modules/react-native + // reactNativeDir = file("../../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen + // codegenDir = file("../../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js + // cliFile = file("../../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] + + /* Autolinking */ + autolinkLibrariesWithApp() +} + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +android { + ndkVersion rootProject.ext.ndkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdk rootProject.ext.compileSdkVersion + + namespace "com.foodly" + defaultConfig { + applicationId "com.foodly" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + release { + if (project.hasProperty('RELEASE_STORE_FILE')) { + storeFile file(RELEASE_STORE_FILE) + storePassword RELEASE_STORE_PASSWORD + keyAlias RELEASE_KEY_ALIAS + keyPassword RELEASE_KEY_PASSWORD + } + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.release +// minifyEnabled enableProguardInReleaseBuilds +// proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + lint { + baseline = file("lint-baseline.xml") + } + flavorDimensions "default" + productFlavors { + localbuild { + dimension "default" + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} diff --git a/front/foodly_application/android/app/debug.keystore b/front/foodly_application/android/app/debug.keystore new file mode 100644 index 0000000..364e105 Binary files /dev/null and b/front/foodly_application/android/app/debug.keystore differ diff --git a/front/foodly_application/android/app/lint-baseline.xml b/front/foodly_application/android/app/lint-baseline.xml new file mode 100644 index 0000000..cd5d163 --- /dev/null +++ b/front/foodly_application/android/app/lint-baseline.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/foodly_application/android/app/proguard-rules.pro b/front/foodly_application/android/app/proguard-rules.pro new file mode 100644 index 0000000..11b0257 --- /dev/null +++ b/front/foodly_application/android/app/proguard-rules.pro @@ -0,0 +1,10 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: diff --git a/front/foodly_application/android/app/src/debug/AndroidManifest.xml b/front/foodly_application/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..eb98c01 --- /dev/null +++ b/front/foodly_application/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/front/foodly_application/android/app/src/main/AndroidManifest.xml b/front/foodly_application/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2113e6c --- /dev/null +++ b/front/foodly_application/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/front/foodly_application/android/app/src/main/java/com/foodly/MainActivity.kt b/front/foodly_application/android/app/src/main/java/com/foodly/MainActivity.kt new file mode 100644 index 0000000..cccb44a --- /dev/null +++ b/front/foodly_application/android/app/src/main/java/com/foodly/MainActivity.kt @@ -0,0 +1,22 @@ +package com.foodly + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "Foodly" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate = + DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) +} diff --git a/front/foodly_application/android/app/src/main/java/com/foodly/MainApplication.kt b/front/foodly_application/android/app/src/main/java/com/foodly/MainApplication.kt new file mode 100644 index 0000000..d4681f1 --- /dev/null +++ b/front/foodly_application/android/app/src/main/java/com/foodly/MainApplication.kt @@ -0,0 +1,44 @@ +package com.foodly + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.soloader.OpenSourceMergedSoMapping +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, OpenSourceMergedSoMapping) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + } +} diff --git a/front/foodly_application/android/app/src/main/res/drawable/rn_edit_text_material.xml b/front/foodly_application/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 0000000..5c25e72 --- /dev/null +++ b/front/foodly_application/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + diff --git a/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..5eaab4d Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..557f3df Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..6013836 Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..4b9222d Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..ac5bb03 Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..032cf81 Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..4740605 Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..ca06987 Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..074775f Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..cda041e Binary files /dev/null and b/front/foodly_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/front/foodly_application/android/app/src/main/res/values/strings.xml b/front/foodly_application/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..95cfa67 --- /dev/null +++ b/front/foodly_application/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Foodly + diff --git a/front/foodly_application/android/app/src/main/res/values/styles.xml b/front/foodly_application/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..7ba83a2 --- /dev/null +++ b/front/foodly_application/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/front/foodly_application/android/build.gradle b/front/foodly_application/android/build.gradle new file mode 100644 index 0000000..a62d6da --- /dev/null +++ b/front/foodly_application/android/build.gradle @@ -0,0 +1,21 @@ +buildscript { + ext { + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + compileSdkVersion = 35 + targetSdkVersion = 34 + ndkVersion = "27.1.12297006" + kotlinVersion = "2.0.21" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") + } +} + +apply plugin: "com.facebook.react.rootproject" diff --git a/front/foodly_application/android/gradle.properties b/front/foodly_application/android/gradle.properties new file mode 100644 index 0000000..be097f7 --- /dev/null +++ b/front/foodly_application/android/gradle.properties @@ -0,0 +1,47 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true + +android.enableJetifier=true + +# Release build config +RELEASE_STORE_FILE=app-release-key.keystore +RELEASE_KEY_ALIAS=app-release +RELEASE_STORE_PASSWORD=nlp_ai_shopper_T734 +RELEASE_KEY_PASSWORD=nlp_ai_shopper_T734 \ No newline at end of file diff --git a/front/foodly_application/android/gradle/wrapper/gradle-wrapper.jar b/front/foodly_application/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/front/foodly_application/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/front/foodly_application/android/gradle/wrapper/gradle-wrapper.properties b/front/foodly_application/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..79eb9d0 --- /dev/null +++ b/front/foodly_application/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/front/foodly_application/android/gradlew b/front/foodly_application/android/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/front/foodly_application/android/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/front/foodly_application/android/gradlew.bat b/front/foodly_application/android/gradlew.bat new file mode 100644 index 0000000..9b42019 --- /dev/null +++ b/front/foodly_application/android/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/front/foodly_application/android/settings.gradle b/front/foodly_application/android/settings.gradle new file mode 100644 index 0000000..65c478a --- /dev/null +++ b/front/foodly_application/android/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } +plugins { id("com.facebook.react.settings") } +extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } +rootProject.name = 'Foodly' +include ':app' +includeBuild('../node_modules/@react-native/gradle-plugin') + +include ':react-native-config' +project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android') + diff --git a/front/foodly_application/app.json b/front/foodly_application/app.json new file mode 100644 index 0000000..947f043 --- /dev/null +++ b/front/foodly_application/app.json @@ -0,0 +1,4 @@ +{ + "name": "Foodly", + "displayName": "Foodly" +} diff --git a/front/foodly_application/babel.config.js b/front/foodly_application/babel.config.js new file mode 100644 index 0000000..02c7d13 --- /dev/null +++ b/front/foodly_application/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: ['module:@react-native/babel-preset'], + plugins: ['react-native-reanimated/plugin'], +}; diff --git a/front/foodly_application/index.js b/front/foodly_application/index.js new file mode 100644 index 0000000..69303b3 --- /dev/null +++ b/front/foodly_application/index.js @@ -0,0 +1,9 @@ +/** + * @format + */ + +import {AppRegistry} from 'react-native'; +import App from './src/App'; +import {name as appName} from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/front/foodly_application/ios/.xcode.env b/front/foodly_application/ios/.xcode.env new file mode 100644 index 0000000..3d5782c --- /dev/null +++ b/front/foodly_application/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/front/foodly_application/ios/Config.xcconfig b/front/foodly_application/ios/Config.xcconfig new file mode 100644 index 0000000..17b7708 --- /dev/null +++ b/front/foodly_application/ios/Config.xcconfig @@ -0,0 +1,11 @@ +// +// Config.xcconfig +// Foodly +// +// Created by ๊น€์ง„์žฌ on 2/2/25. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include? "tmp.xcconfig" diff --git a/front/foodly_application/ios/Foodly.xcodeproj/project.pbxproj b/front/foodly_application/ios/Foodly.xcodeproj/project.pbxproj new file mode 100644 index 0000000..935dd78 --- /dev/null +++ b/front/foodly_application/ios/Foodly.xcodeproj/project.pbxproj @@ -0,0 +1,488 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0C80B921A6F3F58F76C31292 /* libPods-Foodly.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-Foodly.a */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 514E9DA98FF65FF5E2DE26ED /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; + 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + B06EBCA52D4F53E200804AFB /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = B06EBCA42D4F53E200804AFB /* Config.xcconfig */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 13B07F961A680F5B00A75B9A /* Foodly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Foodly.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Foodly/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Foodly/Info.plist; sourceTree = ""; }; + 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = Foodly/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 3B4392A12AC88292D35C810B /* Pods-Foodly.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Foodly.debug.xcconfig"; path = "Target Support Files/Pods-Foodly/Pods-Foodly.debug.xcconfig"; sourceTree = ""; }; + 5709B34CF0A7D63546082F79 /* Pods-Foodly.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Foodly.release.xcconfig"; path = "Target Support Files/Pods-Foodly/Pods-Foodly.release.xcconfig"; sourceTree = ""; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-Foodly.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Foodly.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Foodly/AppDelegate.swift; sourceTree = ""; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = Foodly/LaunchScreen.storyboard; sourceTree = ""; }; + B06EBCA42D4F53E200804AFB /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-Foodly.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* Foodly */ = { + isa = PBXGroup; + children = ( + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 761780EC2CA45674006654EE /* AppDelegate.swift */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */, + ); + name = Foodly; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-Foodly.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + B06EBCA42D4F53E200804AFB /* Config.xcconfig */, + 13B07FAE1A68108700A75B9A /* Foodly */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* Foodly.app */, + ); + name = Products; + sourceTree = ""; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-Foodly.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-Foodly.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* Foodly */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Foodly" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Foodly; + productName = Foodly; + productReference = 13B07F961A680F5B00A75B9A /* Foodly.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Foodly" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* Foodly */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B06EBCA52D4F53E200804AFB /* Config.xcconfig in Resources */, + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 514E9DA98FF65FF5E2DE26ED /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Foodly-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Foodly/Pods-Foodly-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-Foodly.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = P5U5DZ7PVC; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Foodly/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = Foodly; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-Foodly.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = P5U5DZ7PVC; + INFOPLIST_FILE = Foodly/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = Foodly; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B06EBCA42D4F53E200804AFB /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + "-DFOLLY_CFG_NO_COROUTINES=1", + "-DFOLLY_HAVE_CLOCK_GETTIME=1", + ); + OTHER_LDFLAGS = "$(inherited) "; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; + USE_HERMES = true; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B06EBCA42D4F53E200804AFB /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + "-DFOLLY_CFG_NO_COROUTINES=1", + "-DFOLLY_HAVE_CLOCK_GETTIME=1", + ); + OTHER_LDFLAGS = "$(inherited) "; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + USE_HERMES = true; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Foodly" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Foodly" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Develop.xcscheme b/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Develop.xcscheme new file mode 100644 index 0000000..3216677 --- /dev/null +++ b/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Develop.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Foodly.xcscheme b/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Foodly.xcscheme new file mode 100644 index 0000000..4ad403e --- /dev/null +++ b/front/foodly_application/ios/Foodly.xcodeproj/xcshareddata/xcschemes/Foodly.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/foodly_application/ios/Foodly.xcworkspace/contents.xcworkspacedata b/front/foodly_application/ios/Foodly.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..474c421 --- /dev/null +++ b/front/foodly_application/ios/Foodly.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/front/foodly_application/ios/Foodly/AppDelegate.swift b/front/foodly_application/ios/Foodly/AppDelegate.swift new file mode 100644 index 0000000..fd0a200 --- /dev/null +++ b/front/foodly_application/ios/Foodly/AppDelegate.swift @@ -0,0 +1,30 @@ +import UIKit +import React +import React_RCTAppDelegate +import ReactAppDependencyProvider + +@main +class AppDelegate: RCTAppDelegate { + override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + self.moduleName = "Foodly" + self.dependencyProvider = RCTAppDependencyProvider() + + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = [:] + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + override func sourceURL(for bridge: RCTBridge) -> URL? { + self.bundleURL() + } + + override func bundleURL() -> URL? { +#if DEBUG + RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") +#else + Bundle.main.url(forResource: "main", withExtension: "jsbundle") +#endif + } +} diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/1024.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000..344961a Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/1024.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120 1.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120 1.png new file mode 100644 index 0000000..c167769 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120 1.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000..c167769 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/120.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/180.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000..cce5c03 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/180.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/40.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000..11e1df5 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/40.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/58.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000..06c8d14 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/58.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/60.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000..e33a094 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/60.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/80.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 0000000..cb32760 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/80.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/87.png b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 0000000..b18e580 Binary files /dev/null and b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/87.png differ diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/Contents.json b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..ad54b31 --- /dev/null +++ b/front/foodly_application/ios/Foodly/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,62 @@ +{ + "images" : [ + { + "filename" : "40.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "60.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "58.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "87.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "80.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "120.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "120 1.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/front/foodly_application/ios/Foodly/Images.xcassets/Contents.json b/front/foodly_application/ios/Foodly/Images.xcassets/Contents.json new file mode 100644 index 0000000..2d92bd5 --- /dev/null +++ b/front/foodly_application/ios/Foodly/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/front/foodly_application/ios/Foodly/Info.plist b/front/foodly_application/ios/Foodly/Info.plist new file mode 100644 index 0000000..f840f25 --- /dev/null +++ b/front/foodly_application/ios/Foodly/Info.plist @@ -0,0 +1,65 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Foodly + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + ec2-3-37-154-18.ap-northeast-2.compute.amazonaws.com + + NSIncludesSubdomains + + NSExceptionAllowsInsecureHTTPLoads + + NSTemporaryExceptionMinimumTLSVersion + TLSv1.1 + + + NSAllowsLocalNetworking + + + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + BASE_URL + ${BASE_URL} + UIViewControllerBasedStatusBarAppearance + + + diff --git a/front/foodly_application/ios/Foodly/LaunchScreen.storyboard b/front/foodly_application/ios/Foodly/LaunchScreen.storyboard new file mode 100644 index 0000000..8956080 --- /dev/null +++ b/front/foodly_application/ios/Foodly/LaunchScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/foodly_application/ios/Foodly/PrivacyInfo.xcprivacy b/front/foodly_application/ios/Foodly/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..41b8317 --- /dev/null +++ b/front/foodly_application/ios/Foodly/PrivacyInfo.xcprivacy @@ -0,0 +1,37 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/front/foodly_application/ios/Podfile b/front/foodly_application/ios/Podfile new file mode 100644 index 0000000..e7d46ec --- /dev/null +++ b/front/foodly_application/ios/Podfile @@ -0,0 +1,35 @@ +# Resolve react_native_pods.rb with node to allow for hoisting +require Pod::Executable.execute_command('node', ['-p', + 'require.resolve( + "react-native/scripts/react_native_pods.rb", + {paths: [process.argv[1]]}, + )', __dir__]).strip + +platform :ios, min_ios_version_supported +prepare_react_native_project! + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'Foodly' do + config = use_native_modules! + + use_react_native!( + :path => config[:reactNativePath], + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + post_install do |installer| + # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 + react_native_post_install( + installer, + config[:reactNativePath], + :mac_catalyst_enabled => false, + # :ccache_enabled => true + ) + end +end diff --git a/front/foodly_application/ios/Podfile.lock b/front/foodly_application/ios/Podfile.lock new file mode 100644 index 0000000..c48093d --- /dev/null +++ b/front/foodly_application/ios/Podfile.lock @@ -0,0 +1,2081 @@ +PODS: + - boost (1.84.0) + - DoubleConversion (1.1.6) + - fast_float (6.1.4) + - FBLazyVector (0.77.0) + - fmt (11.0.2) + - glog (0.3.5) + - hermes-engine (0.77.0): + - hermes-engine/Pre-built (= 0.77.0) + - hermes-engine/Pre-built (0.77.0) + - RCT-Folly (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - RCT-Folly/Default (= 2024.11.18.00) + - RCT-Folly/Default (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - RCT-Folly/Fabric (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - RCTDeprecation (0.77.0) + - RCTRequired (0.77.0) + - RCTTypeSafety (0.77.0): + - FBLazyVector (= 0.77.0) + - RCTRequired (= 0.77.0) + - React-Core (= 0.77.0) + - React (0.77.0): + - React-Core (= 0.77.0) + - React-Core/DevSupport (= 0.77.0) + - React-Core/RCTWebSocket (= 0.77.0) + - React-RCTActionSheet (= 0.77.0) + - React-RCTAnimation (= 0.77.0) + - React-RCTBlob (= 0.77.0) + - React-RCTImage (= 0.77.0) + - React-RCTLinking (= 0.77.0) + - React-RCTNetwork (= 0.77.0) + - React-RCTSettings (= 0.77.0) + - React-RCTText (= 0.77.0) + - React-RCTVibration (= 0.77.0) + - React-callinvoker (0.77.0) + - React-Core (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/CoreModulesHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/Default (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/DevSupport (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.0) + - React-Core/RCTWebSocket (= 0.77.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTActionSheetHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTAnimationHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTBlobHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTImageHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTLinkingHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTNetworkHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTSettingsHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTTextHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTVibrationHeaders (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-Core/RCTWebSocket (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.7.1) + - Yoga + - React-CoreModules (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety (= 0.77.0) + - React-Core/CoreModulesHeaders (= 0.77.0) + - React-jsi (= 0.77.0) + - React-jsinspector + - React-NativeModulesApple + - React-RCTBlob + - React-RCTFBReactNativeSpec + - React-RCTImage (= 0.77.0) + - ReactCommon + - SocketRocket (= 0.7.1) + - React-cxxreact (0.77.0): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.0) + - React-debug (= 0.77.0) + - React-jsi (= 0.77.0) + - React-jsinspector + - React-logger (= 0.77.0) + - React-perflogger (= 0.77.0) + - React-runtimeexecutor (= 0.77.0) + - React-timing (= 0.77.0) + - React-debug (0.77.0) + - React-defaultsnativemodule (0.77.0): + - hermes-engine + - RCT-Folly + - React-domnativemodule + - React-featureflagsnativemodule + - React-idlecallbacksnativemodule + - React-jsi + - React-jsiexecutor + - React-microtasksnativemodule + - React-RCTFBReactNativeSpec + - React-domnativemodule (0.77.0): + - hermes-engine + - RCT-Folly + - React-Fabric + - React-FabricComponents + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - Yoga + - React-Fabric (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/animations (= 0.77.0) + - React-Fabric/attributedstring (= 0.77.0) + - React-Fabric/componentregistry (= 0.77.0) + - React-Fabric/componentregistrynative (= 0.77.0) + - React-Fabric/components (= 0.77.0) + - React-Fabric/core (= 0.77.0) + - React-Fabric/dom (= 0.77.0) + - React-Fabric/imagemanager (= 0.77.0) + - React-Fabric/leakchecker (= 0.77.0) + - React-Fabric/mounting (= 0.77.0) + - React-Fabric/observers (= 0.77.0) + - React-Fabric/scheduler (= 0.77.0) + - React-Fabric/telemetry (= 0.77.0) + - React-Fabric/templateprocessor (= 0.77.0) + - React-Fabric/uimanager (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/animations (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/attributedstring (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistry (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistrynative (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/components/legacyviewmanagerinterop (= 0.77.0) + - React-Fabric/components/root (= 0.77.0) + - React-Fabric/components/view (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/legacyviewmanagerinterop (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/root (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/view (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-Fabric/core (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/dom (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/imagemanager (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/leakchecker (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/mounting (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/observers (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/observers/events (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/observers/events (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/scheduler (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/observers/events + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-performancetimeline + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/telemetry (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/templateprocessor (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/uimanager (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/uimanager/consistency (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/uimanager/consistency (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-FabricComponents (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components (= 0.77.0) + - React-FabricComponents/textlayoutmanager (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 0.77.0) + - React-FabricComponents/components/iostextinput (= 0.77.0) + - React-FabricComponents/components/modal (= 0.77.0) + - React-FabricComponents/components/rncore (= 0.77.0) + - React-FabricComponents/components/safeareaview (= 0.77.0) + - React-FabricComponents/components/scrollview (= 0.77.0) + - React-FabricComponents/components/text (= 0.77.0) + - React-FabricComponents/components/textinput (= 0.77.0) + - React-FabricComponents/components/unimplementedview (= 0.77.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/inputaccessory (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/iostextinput (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/modal (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/rncore (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/safeareaview (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/scrollview (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/text (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/textinput (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/components/unimplementedview (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricComponents/textlayoutmanager (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - Yoga + - React-FabricImage (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired (= 0.77.0) + - RCTTypeSafety (= 0.77.0) + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsiexecutor (= 0.77.0) + - React-logger + - React-rendererdebug + - React-utils + - ReactCommon + - Yoga + - React-featureflags (0.77.0) + - React-featureflagsnativemodule (0.77.0): + - hermes-engine + - RCT-Folly + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - React-graphics (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-jsi + - React-jsiexecutor + - React-utils + - React-hermes (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact (= 0.77.0) + - React-jsi + - React-jsiexecutor (= 0.77.0) + - React-jsinspector + - React-perflogger (= 0.77.0) + - React-runtimeexecutor + - React-idlecallbacksnativemodule (0.77.0): + - hermes-engine + - RCT-Folly + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimescheduler + - ReactCommon/turbomodule/core + - React-ImageManager (0.77.0): + - glog + - RCT-Folly/Fabric + - React-Core/Default + - React-debug + - React-Fabric + - React-graphics + - React-rendererdebug + - React-utils + - React-jserrorhandler (0.77.0): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - ReactCommon/turbomodule/bridging + - React-jsi (0.77.0): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-jsiexecutor (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact (= 0.77.0) + - React-jsi (= 0.77.0) + - React-jsinspector + - React-perflogger (= 0.77.0) + - React-jsinspector (0.77.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-featureflags + - React-jsi + - React-perflogger (= 0.77.0) + - React-runtimeexecutor (= 0.77.0) + - React-jsitracing (0.77.0): + - React-jsi + - React-logger (0.77.0): + - glog + - React-Mapbuffer (0.77.0): + - glog + - React-debug + - React-microtasksnativemodule (0.77.0): + - hermes-engine + - RCT-Folly + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - react-native-config (1.5.3): + - react-native-config/App (= 1.5.3) + - react-native-config/App (1.5.3): + - React-Core + - react-native-safe-area-context (5.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common (= 5.1.0) + - react-native-safe-area-context/fabric (= 5.1.0) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/common (5.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/fabric (5.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-splash-screen (3.3.0): + - React-Core + - React-nativeconfig (0.77.0) + - React-NativeModulesApple (0.77.0): + - glog + - hermes-engine + - React-callinvoker + - React-Core + - React-cxxreact + - React-jsi + - React-jsinspector + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-perflogger (0.77.0): + - DoubleConversion + - RCT-Folly (= 2024.11.18.00) + - React-performancetimeline (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact + - React-featureflags + - React-timing + - React-RCTActionSheet (0.77.0): + - React-Core/RCTActionSheetHeaders (= 0.77.0) + - React-RCTAnimation (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety + - React-Core/RCTAnimationHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - React-RCTAppDelegate (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-CoreModules + - React-debug + - React-defaultsnativemodule + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-nativeconfig + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTNetwork + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - ReactCommon + - React-RCTBlob (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-Core/RCTBlobHeaders + - React-Core/RCTWebSocket + - React-jsi + - React-jsinspector + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - React-RCTFabric (0.77.0): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-Core + - React-debug + - React-Fabric + - React-FabricComponents + - React-FabricImage + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-nativeconfig + - React-performancetimeline + - React-RCTImage + - React-RCTText + - React-rendererconsistency + - React-rendererdebug + - React-runtimescheduler + - React-utils + - Yoga + - React-RCTFBReactNativeSpec (0.77.0): + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - ReactCommon + - React-RCTImage (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety + - React-Core/RCTImageHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - React-RCTLinking (0.77.0): + - React-Core/RCTLinkingHeaders (= 0.77.0) + - React-jsi (= 0.77.0) + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactCommon/turbomodule/core (= 0.77.0) + - React-RCTNetwork (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety + - React-Core/RCTNetworkHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - React-RCTSettings (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety + - React-Core/RCTSettingsHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - React-RCTText (0.77.0): + - React-Core/RCTTextHeaders (= 0.77.0) + - Yoga + - React-RCTVibration (0.77.0): + - RCT-Folly (= 2024.11.18.00) + - React-Core/RCTVibrationHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - React-rendererconsistency (0.77.0) + - React-rendererdebug (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - RCT-Folly (= 2024.11.18.00) + - React-debug + - React-rncore (0.77.0) + - React-RuntimeApple (0.77.0): + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-callinvoker + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - React-RuntimeCore (0.77.0): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-cxxreact + - React-Fabric + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-performancetimeline + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - React-runtimeexecutor (0.77.0): + - React-jsi (= 0.77.0) + - React-RuntimeHermes (0.77.0): + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-featureflags + - React-hermes + - React-jsi + - React-jsinspector + - React-jsitracing + - React-nativeconfig + - React-RuntimeCore + - React-utils + - React-runtimescheduler (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-performancetimeline + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-timing + - React-utils + - React-timing (0.77.0) + - React-utils (0.77.0): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-debug + - React-jsi (= 0.77.0) + - ReactAppDependencyProvider (0.77.0): + - ReactCodegen + - ReactCodegen (0.77.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-FabricImage + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-RCTAppDelegate + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactCommon (0.77.0): + - ReactCommon/turbomodule (= 0.77.0) + - ReactCommon/turbomodule (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.0) + - React-cxxreact (= 0.77.0) + - React-jsi (= 0.77.0) + - React-logger (= 0.77.0) + - React-perflogger (= 0.77.0) + - ReactCommon/turbomodule/bridging (= 0.77.0) + - ReactCommon/turbomodule/core (= 0.77.0) + - ReactCommon/turbomodule/bridging (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.0) + - React-cxxreact (= 0.77.0) + - React-jsi (= 0.77.0) + - React-logger (= 0.77.0) + - React-perflogger (= 0.77.0) + - ReactCommon/turbomodule/core (0.77.0): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.0) + - React-cxxreact (= 0.77.0) + - React-debug (= 0.77.0) + - React-featureflags (= 0.77.0) + - React-jsi (= 0.77.0) + - React-logger (= 0.77.0) + - React-perflogger (= 0.77.0) + - React-utils (= 0.77.0) + - RNGestureHandler (2.22.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNReanimated (3.16.7): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated (= 3.16.7) + - RNReanimated/worklets (= 3.16.7) + - Yoga + - RNReanimated/reanimated (3.16.7): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated/apple (= 3.16.7) + - Yoga + - RNReanimated/reanimated/apple (3.16.7): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNReanimated/worklets (3.16.7): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNScreens (4.5.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.5.0) + - Yoga + - RNScreens/common (4.5.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNSVG (15.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNSVG/common (= 15.11.1) + - Yoga + - RNSVG/common (15.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - SocketRocket (0.7.1) + - Yoga (0.0.0) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) + - RCTRequired (from `../node_modules/react-native/Libraries/Required`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) + - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) + - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) + - React-FabricImage (from `../node_modules/react-native/ReactCommon`) + - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) + - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) + - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) + - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) + - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) + - react-native-config (from `../node_modules/react-native-config`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - react-native-splash-screen (from `../node_modules/react-native-splash-screen`) + - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTFabric (from `../node_modules/react-native/React`) + - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) + - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) + - React-rncore (from `../node_modules/react-native/ReactCommon`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - ReactAppDependencyProvider (from `build/generated/ios`) + - ReactCodegen (from `build/generated/ios`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) + - RNReanimated (from `../node_modules/react-native-reanimated`) + - RNScreens (from `../node_modules/react-native-screens`) + - RNSVG (from `../node_modules/react-native-svg`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - SocketRocket + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + fast_float: + :podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + fmt: + :podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2024-11-25-RNv0.77.0-d4f25d534ab744866448b36ca3bf3d97c08e638c + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTDeprecation: + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" + RCTRequired: + :path: "../node_modules/react-native/Libraries/Required" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + React-domnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" + React-Fabric: + :path: "../node_modules/react-native/ReactCommon" + React-FabricComponents: + :path: "../node_modules/react-native/ReactCommon" + React-FabricImage: + :path: "../node_modules/react-native/ReactCommon" + React-featureflags: + :path: "../node_modules/react-native/ReactCommon/react/featureflags" + React-featureflagsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" + React-graphics: + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + React-jserrorhandler: + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + React-Mapbuffer: + :path: "../node_modules/react-native/ReactCommon" + React-microtasksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + react-native-config: + :path: "../node_modules/react-native-config" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + react-native-splash-screen: + :path: "../node_modules/react-native-splash-screen" + React-nativeconfig: + :path: "../node_modules/react-native/ReactCommon" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-performancetimeline: + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTFabric: + :path: "../node_modules/react-native/React" + React-RCTFBReactNativeSpec: + :path: "../node_modules/react-native/React" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererconsistency: + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" + React-rendererdebug: + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" + React-rncore: + :path: "../node_modules/react-native/ReactCommon" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-timing: + :path: "../node_modules/react-native/ReactCommon/react/timing" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + ReactAppDependencyProvider: + :path: build/generated/ios + ReactCodegen: + :path: build/generated/ios + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + RNGestureHandler: + :path: "../node_modules/react-native-gesture-handler" + RNReanimated: + :path: "../node_modules/react-native-reanimated" + RNScreens: + :path: "../node_modules/react-native-screens" + RNSVG: + :path: "../node_modules/react-native-svg" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 + DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb + fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 + FBLazyVector: 2bc03a5cf64e29c611bbc5d7eb9d9f7431f37ee6 + fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd + glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8 + hermes-engine: 1f783c3d53940aed0d2c84586f0b7a85ab7827ef + RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCTDeprecation: f5c19ebdb8804b53ed029123eb69914356192fc8 + RCTRequired: 6ae6cebe470486e0e0ce89c1c0eabb998e7c51f4 + RCTTypeSafety: 50d6ec72a3d13cf77e041ff43a0617050fb98e3f + React: e46fdbd82d2de942970c106677056f3bdd438d82 + React-callinvoker: b027ad895934b5f27ce166d095ed0d272d7df619 + React-Core: 92733c8280b1642afed7ebfb3c523feaec946ece + React-CoreModules: e2dfd87b6fdb9d969b16871655885a4d89a2a9f4 + React-cxxreact: d1a70e78543bb5b159fdaf6c52cadd33c1ae3244 + React-debug: 78d7544d2750737ac3acc88cca2f457d081ec43d + React-defaultsnativemodule: b24e61fe2d5bb84501898683f9d13ff7fc02a9df + React-domnativemodule: 210ca3670f16ae92fbcff8da204750af8a7295af + React-Fabric: 4b3d03ea38646dcc80888253c2befca80526abed + React-FabricComponents: 38fcb6f5c08f8de9e693f2644d2da54ae4fbf6c8 + React-FabricImage: 1d37769002c13dfffa9f53557a173d56c9ade5e3 + React-featureflags: 92dd7d0169ab0bf8ad404a5fe757c1ca7ccd74e8 + React-featureflagsnativemodule: 8a6373d7b4ef3c08d82b60376f75bd189bfc8cb2 + React-graphics: 2b316fcf5b6c29ded7d53ae0007d1d129dc89510 + React-hermes: bf50c8272cb562300a54a621aa69dc12a0b4fcf2 + React-idlecallbacksnativemodule: 47df5b6649ca5e0046aa3e43e680452007b16871 + React-ImageManager: 83b8dc67e97cd5fe10cb715bd878aded16adb40f + React-jserrorhandler: ac08c5673dea69b08e11faf074fd602fbf9492cc + React-jsi: 19e77567e235d06b7e8f425d2a6c1e948ab286e9 + React-jsiexecutor: fe6ad8b9a2bf97e435fc1c969c80ed7f447ed68e + React-jsinspector: f321d958a5534b65b56f7806c674e159c28f7d69 + React-jsitracing: d358876acde46009f391228b932a5efe13c8895b + React-logger: 02e5802824aa9b15cb7df42e10a91abead83cd8d + React-Mapbuffer: 99bd566147aaa78e872568be53ebca8a4449ddae + React-microtasksnativemodule: 51e7813abf875408a0f367e473a65bbab6aa8481 + react-native-config: ea75335a7cca1d3326de1da384227e580a7c082e + react-native-safe-area-context: efd435f89b73d91f37438e5ac2d725f0e7adff95 + react-native-splash-screen: 95994222cc95c236bd3cdc59fe45ed5f27969594 + React-nativeconfig: cd0fbb40987a9658c24dab5812c14e5522a64929 + React-NativeModulesApple: 4a9c304aa4fb086af32e8758ba892386d895b4d3 + React-perflogger: 721172bda31a65ce7b7a0c3bf3de96f12ef6f45d + React-performancetimeline: 46dbe9fd618ff882f59600dcd9fa923a9713cc3b + React-RCTActionSheet: 25eb72eabade4095bfaf6cd9c5c965c76865daa8 + React-RCTAnimation: 8efbd0a4a71fd3dbe84e6d08b92bec5728b7524b + React-RCTAppDelegate: 8ff6da817adefd15d4e25ade53a477c344f9b213 + React-RCTBlob: 6056bd62a56a6d2dad55cdf195949db1de623e14 + React-RCTFabric: 949589de63c19b8b197555567fbc51eebd265bbc + React-RCTFBReactNativeSpec: 4214925b1c4829fb1e73bfbacb301244b522dc11 + React-RCTImage: 7b3f38c77e183bdcb43dbcd7b5842b96c814889a + React-RCTLinking: 6cca74db71b23f670b72e45603e615c2b72b2235 + React-RCTNetwork: 5791b0718eff20c12f6f3d62e2ad50cff4b5c8a0 + React-RCTSettings: 84154e31a232b5b03b6b7a89924a267c431ccf16 + React-RCTText: cd49cb4442ee7f64b0415b27745d2495cb40cfaa + React-RCTVibration: 2a7432e61d42f802716bd67edc793b5e5f58971a + React-rendererconsistency: 7a81b08f01655b458d1de48ddd5b3f5988fd753f + React-rendererdebug: a6547cf2f3f7bcdd8d36ff5e103145d83f5001d4 + React-rncore: dd08c91cea25486f79012e32975c0ea26bd92760 + React-RuntimeApple: ea09b4c38df2695e0cb3fa60a83db81d653a39fd + React-RuntimeCore: 3dc763d365a1f738d92cd942066dd347953733f3 + React-runtimeexecutor: f9ae11481be048438640085c1e8266d6afebae44 + React-RuntimeHermes: 3bc16b5a5a756a292ad6f56968dfb8de643ae20b + React-runtimescheduler: 2e90401c400b62bb720d6ac028dcef803e30d888 + React-timing: 0d0263a5d8ab6fc8c325efb54cee1d6a6f01d657 + React-utils: 8905cd01f46755ea42268875d04c614a0d46431e + ReactAppDependencyProvider: 6e8d68583f39dc31ee65235110287277eb8556ef + ReactCodegen: c08a5113d9c9c895fe10f3c296f74c6b705a60a9 + ReactCommon: 1bd2dc684d7992acbf0dfee887b89a57a1ead86d + RNGestureHandler: 657b9ff1f40ee3ace3de2bcf467f86d9a6874197 + RNReanimated: 8a4ea733f88a33379150eb2e73b375e14de81e84 + RNScreens: 5d61e452b51e7c23b3fcb9f16c4967d683a60a9d + RNSVG: 2089e8b3a145acb2f392017279790f007f934567 + SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 + Yoga: 78d74e245ed67bb94275a1316cdc170b9b7fe884 + +PODFILE CHECKSUM: 9cf158aa4a386c323b8238ebc6a8e3c77376fcef + +COCOAPODS: 1.16.2 diff --git a/front/foodly_application/ios/tmp.xcconfig b/front/foodly_application/ios/tmp.xcconfig new file mode 100644 index 0000000..b369240 --- /dev/null +++ b/front/foodly_application/ios/tmp.xcconfig @@ -0,0 +1 @@ +BASE_URL=http:/$()/ec2-3-37-154-18.ap-northeast-2.compute.amazonaws.com:8080 diff --git a/front/foodly_application/jest.config.js b/front/foodly_application/jest.config.js new file mode 100644 index 0000000..8eb675e --- /dev/null +++ b/front/foodly_application/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'react-native', +}; diff --git a/front/foodly_application/metro.config.js b/front/foodly_application/metro.config.js new file mode 100644 index 0000000..ba95bf4 --- /dev/null +++ b/front/foodly_application/metro.config.js @@ -0,0 +1,11 @@ +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +/** + * Metro configuration + * https://reactnative.dev/docs/metro + * + * @type {import('@react-native/metro-config').MetroConfig} + */ +const config = {}; + +module.exports = mergeConfig(getDefaultConfig(__dirname), config); diff --git a/front/foodly_application/package-lock.json b/front/foodly_application/package-lock.json new file mode 100644 index 0000000..6ba0bc0 --- /dev/null +++ b/front/foodly_application/package-lock.json @@ -0,0 +1,13513 @@ +{ + "name": "foodly", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "foodly", + "version": "0.0.1", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-regular-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/react-native-fontawesome": "^0.3.2", + "@react-navigation/bottom-tabs": "^7.2.0", + "@react-navigation/native": "^7.0.14", + "@react-navigation/stack": "^7.1.1", + "axios": "^1.7.9", + "react": "18.3.1", + "react-native": "0.77.0", + "react-native-config": "^1.5.3", + "react-native-gesture-handler": "^2.22.1", + "react-native-reanimated": "^3.16.7", + "react-native-safe-area-context": "^5.1.0", + "react-native-screens": "^4.5.0", + "react-native-splash-screen": "^3.3.0", + "react-native-svg": "^15.11.1" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.3", + "@babel/runtime": "^7.25.0", + "@react-native-community/cli": "15.0.1", + "@react-native-community/cli-platform-android": "15.0.1", + "@react-native-community/cli-platform-ios": "15.0.1", + "@react-native/babel-preset": "0.77.0", + "@react-native/eslint-config": "0.77.0", + "@react-native/metro-config": "0.77.0", + "@react-native/typescript-config": "0.77.0", + "@types/jest": "^29.5.13", + "@types/react": "^18.2.6", + "@types/react-native-vector-icons": "^6.4.18", + "@types/react-test-renderer": "^18.0.0", + "eslint": "^8.19.0", + "jest": "^29.6.3", + "prettier": "2.8.8", + "react-test-renderer": "18.3.1", + "typescript": "5.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", + "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz", + "integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.7", + "@babel/parser": "^7.26.7", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.26.7", + "@babel/types": "^7.26.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.26.5.tgz", + "integrity": "sha512-Kkm8C8uxI842AwQADxl0GbcG1rupELYLShazYEZO/2DYjhyWXJIOUVOE3tBYm6JXzUCNJOZEzqc4rCW/jsEQYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", + "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", + "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", + "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz", + "integrity": "sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.9.tgz", + "integrity": "sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", + "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz", + "integrity": "sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-flow": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", + "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.7.tgz", + "integrity": "sha512-5cJurntg+AT+cgelGP9Bt788DKiAw9gIMSMU2NJrLAilnj0m8WZWUNZPSLOmadYsujHutpgElO+50foX+ib/Wg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz", + "integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.26.3", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.9.tgz", + "integrity": "sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.9.tgz", + "integrity": "sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/register/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", + "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", + "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.7", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse--for-generate-function-map": { + "name": "@babel/traverse", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", + "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.7", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", + "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@egjs/hammerjs": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", + "license": "MIT", + "dependencies": { + "@types/hammerjs": "^2.0.36" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz", + "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz", + "integrity": "sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", + "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-native-fontawesome": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-native-fontawesome/-/react-native-fontawesome-0.3.2.tgz", + "integrity": "sha512-CiWfJWSZHRg12VXlaeFnaa5yJVPOrjsSFEvF6ntz3cnjg4oN3cvauL+JATacMCl0v9xzib32qC1WZAvvGkfB4w==", + "license": "MIT", + "dependencies": { + "humps": "^2.0.1", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react-native": ">= 0.67", + "react-native-svg": ">= 11.x" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-native-community/cli": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-15.0.1.tgz", + "integrity": "sha512-xIGPytx2bj5HxFk0c7S25AVuJowHmEFg5LFC9XosKc0TSOjP1r6zGC6OqC/arQV/pNuqmZN2IFnpgJn0Bn+hhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-clean": "15.0.1", + "@react-native-community/cli-config": "15.0.1", + "@react-native-community/cli-debugger-ui": "15.0.1", + "@react-native-community/cli-doctor": "15.0.1", + "@react-native-community/cli-server-api": "15.0.1", + "@react-native-community/cli-tools": "15.0.1", + "@react-native-community/cli-types": "15.0.1", + "chalk": "^4.1.2", + "commander": "^9.4.1", + "deepmerge": "^4.3.0", + "execa": "^5.0.0", + "find-up": "^5.0.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.1.3", + "prompts": "^2.4.2", + "semver": "^7.5.2" + }, + "bin": { + "rnc-cli": "build/bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native-community/cli-clean": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-15.0.1.tgz", + "integrity": "sha512-flGTfT005UZvW2LAXVowZ/7ri22oiiZE4pPgMvc8klRxO5uofKIRuohgiHybHtiCo/HNqIz45JmZJvuFrhc4Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-glob": "^3.3.2" + } + }, + "node_modules/@react-native-community/cli-config": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-15.0.1.tgz", + "integrity": "sha512-SL3/9zIyzQQPKWei0+W1gNHxCPurrxqpODUWnVLoP38DNcvYCGtsRayw/4DsXgprZfBC+FsscNpd3IDJrG59XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "cosmiconfig": "^9.0.0", + "deepmerge": "^4.3.0", + "fast-glob": "^3.3.2", + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli-config-apple": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config-apple/-/cli-config-apple-15.0.1.tgz", + "integrity": "sha512-GEHUx4NRp9W9or6vygn0TgNeFkcJdNjrtko0vQEJAS4gJdWqP/9LqqwJNlUfaW5jHBN7TKALAMlfRmI12Op3sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-glob": "^3.3.2" + } + }, + "node_modules/@react-native-community/cli-debugger-ui": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-15.0.1.tgz", + "integrity": "sha512-xkT2TLS8zg5r7Vl9l/2f7JVUoFECnVBS+B5ivrSu2PNZhKkr9lRmJFxC9aVLFb5lIxQQKNDvEyiIDNfP7wjJiA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@react-native-community/cli-doctor": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-15.0.1.tgz", + "integrity": "sha512-YCu44lZR3zZxJJYVTqYZFz9cT9KBfbKI4q2MnKOvkamt00XY3usooMqfuwBAdvM/yvpx7M5w8kbM/nPyj4YCvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-config": "15.0.1", + "@react-native-community/cli-platform-android": "15.0.1", + "@react-native-community/cli-platform-apple": "15.0.1", + "@react-native-community/cli-platform-ios": "15.0.1", + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "deepmerge": "^4.3.0", + "envinfo": "^7.13.0", + "execa": "^5.0.0", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "semver": "^7.5.2", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1", + "yaml": "^2.2.1" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-platform-android": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-15.0.1.tgz", + "integrity": "sha512-QlAMomj6H6TY6pHwjTYMsHDQLP5eLzjAmyW1qb03w/kyS/72elK2bjsklNWJrscFY9TMQLqw7qoAsXf1m5t/dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-glob": "^3.3.2", + "fast-xml-parser": "^4.4.1", + "logkitty": "^0.7.1" + } + }, + "node_modules/@react-native-community/cli-platform-apple": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-apple/-/cli-platform-apple-15.0.1.tgz", + "integrity": "sha512-iQj1Dt2fr/Q7X2CQhyhWnece3eLDCark1osfiwpViksOfTH2WdpNS3lIwlFcIKhsieFU7YYwbNuFqQ3tF9Dlvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-config-apple": "15.0.1", + "@react-native-community/cli-tools": "15.0.1", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.4.1" + } + }, + "node_modules/@react-native-community/cli-platform-ios": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-15.0.1.tgz", + "integrity": "sha512-6pKzXEIgGL20eE1uOn8iSsNBlMzO1LG+pQOk+7mvD172EPhKm/lRzUVDX5gO/2jvsGoNw6VUW0JX1FI2firwqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-platform-apple": "15.0.1" + } + }, + "node_modules/@react-native-community/cli-server-api": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-15.0.1.tgz", + "integrity": "sha512-f3rb3t1ELLaMSX5/LWO/IykglBIgiP3+pPnyl8GphHnBpf3bdIcp7fHlHLemvHE06YxT2nANRxRPjy1gNskenA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@react-native-community/cli-debugger-ui": "15.0.1", + "@react-native-community/cli-tools": "15.0.1", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.1", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^6.2.3" + } + }, + "node_modules/@react-native-community/cli-tools": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-15.0.1.tgz", + "integrity": "sha512-N79A+u/94roanfmNohVcNGu6Xg+0idh63JHZFLC9OJJuZwTifGMLDfSTHZATpR1J7rebozQ5ClcSUePavErnSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "open": "^6.2.0", + "ora": "^5.4.1", + "prompts": "^2.4.2", + "semver": "^7.5.2", + "shell-quote": "^1.7.3", + "sudo-prompt": "^9.0.0" + } + }, + "node_modules/@react-native-community/cli-tools/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native-community/cli-types": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-15.0.1.tgz", + "integrity": "sha512-sWiJ62kkGu2mgYni2dsPxOMBzpwTjNsDH1ubY4mqcNEI9Zmzs0vRwwDUEhYqwNGys9+KpBKoZRrT2PAlhO84xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.77.0.tgz", + "integrity": "sha512-Ms4tYYAMScgINAXIhE4riCFJPPL/yltughHS950l0VP5sm5glbimn9n7RFn9Tc8cipX74/ddbk19+ydK2iDMmA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.77.0.tgz", + "integrity": "sha512-5TYPn1k+jdDOZJU4EVb1kZ0p9TCVICXK3uplRev5Gul57oWesAaiWGZOzfRS3lonWeuR4ij8v8PFfIHOaq0vmA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@react-native/codegen": "0.77.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.77.0.tgz", + "integrity": "sha512-Z4yxE66OvPyQ/iAlaETI1ptRLcDm7Tk6ZLqtCPuUX3AMg+JNgIA86979T4RSk486/JrBUBH5WZe2xjj7eEHXsA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/template": "^7.25.0", + "@react-native/babel-plugin-codegen": "0.77.0", + "babel-plugin-syntax-hermes-parser": "0.25.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.77.0.tgz", + "integrity": "sha512-rE9lXx41ZjvE8cG7e62y/yGqzUpxnSvJ6me6axiX+aDewmI4ZrddvRGYyxCnawxy5dIBHSnrpZse3P87/4Lm7w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.25.1", + "invariant": "^2.2.4", + "jscodeshift": "^17.0.0", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.77.0.tgz", + "integrity": "sha512-GRshwhCHhtupa3yyCbel14SlQligV8ffNYN5L1f8HCo2SeGPsBDNjhj2U+JTrMPnoqpwowPGvkCwyqwqYff4MQ==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.77.0", + "@react-native/metro-babel-transformer": "0.77.0", + "chalk": "^4.0.0", + "debug": "^2.2.0", + "invariant": "^2.2.4", + "metro": "^0.81.0", + "metro-config": "^0.81.0", + "metro-core": "^0.81.0", + "readline": "^1.3.0", + "semver": "^7.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@react-native-community/cli-server-api": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli-server-api": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@react-native/community-cli-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.77.0.tgz", + "integrity": "sha512-glOvSEjCbVXw+KtfiOAmrq21FuLE1VsmBsyT7qud4KWbXP43aUEhzn70mWyFuiIdxnzVPKe2u8iWTQTdJksR1w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.77.0.tgz", + "integrity": "sha512-DAlEYujm43O+Dq98KP2XfLSX5c/TEGtt+JBDEIOQewk374uYY52HzRb1+Gj6tNaEj/b33no4GibtdxbO5zmPhg==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.77.0", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "selfsigned": "^2.4.1", + "serve-static": "^1.16.2", + "ws": "^6.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/eslint-config": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/eslint-config/-/eslint-config-0.77.0.tgz", + "integrity": "sha512-azEiJNe/v1MjXE5Cekn8ygV4an0T3mNem4Afmeaq9tO9rfbOYr3VpTMFgc4B42SZgS4S6lyIqvwTfc8bSp0KRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/eslint-parser": "^7.25.1", + "@react-native/eslint-plugin": "0.77.0", + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^27.9.0", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": ">=8", + "prettier": ">=2" + } + }, + "node_modules/@react-native/eslint-plugin": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/eslint-plugin/-/eslint-plugin-0.77.0.tgz", + "integrity": "sha512-1DXUDiqsgvFpK633SsOF01aAtWAaI/+KqPJAoZOVdSsodk70wNYyrHpF9rJBXWhyT/peTBE5y2kK2kT/Y7JcQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.77.0.tgz", + "integrity": "sha512-rmfh93jzbndSq7kihYHUQ/EGHTP8CCd3GDCmg5SbxSOHAaAYx2HZ28ZG7AVcGUsWeXp+e/90zGIyfOzDRx0Zaw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.77.0.tgz", + "integrity": "sha512-kHFcMJVkGb3ptj3yg1soUsMHATqal4dh0QTGAbYihngJ6zy+TnP65J3GJq4UlwqFE9K1RZkeCmTwlmyPFHOGvA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.77.0.tgz", + "integrity": "sha512-19GfvhBRKCU3UDWwCnDR4QjIzz3B2ZuwhnxMRwfAgPxz7QY9uKour9RGmBAVUk1Wxi/SP7dLEvWnmnuBO39e2A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@react-native/babel-preset": "0.77.0", + "hermes-parser": "0.25.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/metro-config": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.77.0.tgz", + "integrity": "sha512-IhcsIDdoIYkXf3FoZxayRGg2oMLBhpqWEH6IDJlJTQamOQ3PUm2uF1e7yzvnatZ18A6JCNhOlxnBK7m5ZWQPYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/js-polyfills": "0.77.0", + "@react-native/metro-babel-transformer": "0.77.0", + "metro-config": "^0.81.0", + "metro-runtime": "^0.81.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.77.0.tgz", + "integrity": "sha512-qjmxW3xRZe4T0ZBEaXZNHtuUbRgyfybWijf1yUuQwjBt24tSapmIslwhCjpKidA0p93ssPcepquhY0ykH25mew==", + "license": "MIT" + }, + "node_modules/@react-native/typescript-config": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.77.0.tgz", + "integrity": "sha512-WunTrKSQtGKi7gVf24jinHkXXi3tSkChRfrUPFY1njNWwVNtJ/H0ElSlJKUIWaBcd6DKG4ZddKsftWBAWTV0Sg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.77.0.tgz", + "integrity": "sha512-ppPtEu9ISO9iuzpA2HBqrfmDpDAnGGduNDVaegadOzbMCPAB3tC9Blxdu9W68LyYlNQILIsP6/FYtLwf7kfNew==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^18.2.6", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.2.0.tgz", + "integrity": "sha512-1LxjgnbPyFINyf9Qr5d1YE0pYhuJayg5TCIIFQmbcX4PRhX7FKUXV7cX8OzrKXEdZi/UE/VNXugtozPAR9zgvA==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.2.5", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/core": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.3.1.tgz", + "integrity": "sha512-S3KCGvNsoqVk8ErAtQI2EAhg9185lahF5OY01ofrrD4Ij/uk3QEHHjoGQhR5l5DXSCSKr1JbMQA7MEKMsBiWZA==", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.1.2", + "escape-string-regexp": "^4.0.0", + "nanoid": "3.3.8", + "query-string": "^7.1.3", + "react-is": "^18.2.0", + "use-latest-callback": "^0.2.1", + "use-sync-external-store": "^1.2.2" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/@react-navigation/elements": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz", + "integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.14.tgz", + "integrity": "sha512-Gi6lLw4VOGSWAhmUdJOMauOKGK51/YA1CprjXm91sNfgERWvznqEMw8QmUQx9SEqYfi0LfZhbzpMst09SJ00lw==", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.3.1", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "3.3.8", + "use-latest-callback": "^0.2.1" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.1.2.tgz", + "integrity": "sha512-emdEjpVDK8zbiu2GChC8oYIAub9i/OpNuQJekVsbyFCBz4/TzaBzms38Q53YaNhdIFNmiYLfHv/Y1Ub7KYfm3w==", + "license": "MIT", + "dependencies": { + "nanoid": "3.3.8" + } + }, + "node_modules/@react-navigation/stack": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-7.1.1.tgz", + "integrity": "sha512-CBTKQlIkELp05zRiTAv5Pa7OMuCpKyBXcdB3PGMN2Mm55/5MkDsA1IaZorp/6TsVCdllITD6aTbGX/HA/88A6w==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.2.5", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-gesture-handler": ">= 2.0.0", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", + "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-native": { + "version": "0.70.19", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.19.tgz", + "integrity": "sha512-c6WbyCgWTBgKKMESj/8b4w+zWcZSsCforson7UdXtXMecG3MxCinYi6ihhrHVPyUrVzORsvEzK8zg32z4pK6Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-native-vector-icons": { + "version": "6.4.18", + "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.18.tgz", + "integrity": "sha512-YGlNWb+k5laTBHd7+uZowB9DpIK3SXUneZqAiKQaj1jnJCZM0x71GDim5JCTMi4IFkhc9m8H/Gm28T5BjyivUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@types/react-native": "^0.70" + } + }, + "node_modules/@types/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-vAhnk0tG2eGa37lkU9+s5SoroCsRI08xnsWFiAXOuPH2jqzMbcXvKExXViPi1P5fIklDeCvXqyrdmipFaSkZrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "^18" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-fragments": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^1.0.7", + "slice-ansi": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/appdirsjs": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz", + "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.25.1" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "license": "MIT", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "license": "MIT", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001695", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", + "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", + "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/chromium-edge-launcher/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz", + "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==", + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.88", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz", + "integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-plugin-ft-flow": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz", + "integrity": "sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7.12.0", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz", + "integrity": "sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "license": "Apache-2.0" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz", + "integrity": "sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/flow-parser": { + "version": "0.259.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.259.1.tgz", + "integrity": "sha512-xiXLmMH2Z7OmdE9Q+MjljUMr/rbemFqZIRxaeZieVScG4HzQrKKhNcCYZbWTGpoN7ZPi7z8ClQbeVPq6t5AszQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz", + "integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humps": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz", + "integrity": "sha512-E0eIbrFWUhwfXJmsbdjRQFQPrl5pTEoKlz163j1mTqqUnU9PgR4AgB8AIITzuB3vLBdxZXyZ9TDIrwB2OASz4g==", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz", + "integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-android": { + "version": "250231.0.0", + "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", + "integrity": "sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==", + "license": "BSD-2-Clause" + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jscodeshift": { + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-17.1.2.tgz", + "integrity": "sha512-uime4vFOiZ1o3ICT4Sm/AbItHEVw2oCxQ3a0egYVy3JMMOctxe07H3SKL1v175YqjMt27jn1N+3+Bj9SKDNgdQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/preset-flow": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "@babel/register": "^7.24.6", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.7", + "neo-async": "^2.5.0", + "picocolors": "^1.0.1", + "recast": "^0.23.9", + "tmp": "^0.2.3", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "node_modules/jscodeshift/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jscodeshift/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/logkitty": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz", + "integrity": "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-fragments": "^0.2.1", + "dayjs": "^1.8.15", + "yargs": "^15.1.0" + }, + "bin": { + "logkitty": "bin/logkitty.js" + } + }, + "node_modules/logkitty/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/logkitty/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/logkitty/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/logkitty/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logkitty/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.81.0.tgz", + "integrity": "sha512-kzdzmpL0gKhEthZ9aOV7sTqvg6NuTxDV8SIm9pf9sO8VVEbKrQk5DNcwupOUjgPPFAuKUc2NkT0suyT62hm2xg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "denodeify": "^1.2.1", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.24.0", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.81.0", + "metro-cache": "0.81.0", + "metro-cache-key": "0.81.0", + "metro-config": "0.81.0", + "metro-core": "0.81.0", + "metro-file-map": "0.81.0", + "metro-resolver": "0.81.0", + "metro-runtime": "0.81.0", + "metro-source-map": "0.81.0", + "metro-symbolicate": "0.81.0", + "metro-transform-plugins": "0.81.0", + "metro-transform-worker": "0.81.0", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "strip-ansi": "^6.0.0", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.81.0.tgz", + "integrity": "sha512-Dc0QWK4wZIeHnyZ3sevWGTnnSkIDDn/SWyfrn99zbKbDOCoCYy71PAn9uCRrP/hduKLJQOy+tebd63Rr9D8tXg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.24.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.24.0.tgz", + "integrity": "sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.24.0.tgz", + "integrity": "sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.24.0" + } + }, + "node_modules/metro-cache": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.81.0.tgz", + "integrity": "sha512-DyuqySicHXkHUDZFVJmh0ygxBSx6pCKUrTcSgb884oiscV/ROt1Vhye+x+OIHcsodyA10gzZtrVtxIFV4l9I4g==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "metro-core": "0.81.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-cache-key": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.81.0.tgz", + "integrity": "sha512-qX/IwtknP9bQZL78OK9xeSvLM/xlGfrs6SlUGgHvrxtmGTRSsxcyqxR+c+7ch1xr05n62Gin/O44QKg5V70rNQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-config": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.81.0.tgz", + "integrity": "sha512-6CinEaBe3WLpRlKlYXXu8r1UblJhbwD6Gtnoib5U8j6Pjp7XxMG9h/DGMeNp9aGLDu1OieUqiXpFo7O0/rR5Kg==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.6.3", + "metro": "0.81.0", + "metro-cache": "0.81.0", + "metro-core": "0.81.0", + "metro-runtime": "0.81.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/metro-config/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "license": "MIT", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/metro-config/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-core": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.81.0.tgz", + "integrity": "sha512-CVkM5YCOAFkNMvJai6KzA0RpztzfEKRX62/PFMOJ9J7K0uq/UkOFLxcgpcncMIrfy0PbfEj811b69tjULUQe1Q==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.81.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-file-map": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.81.0.tgz", + "integrity": "sha512-zMDI5uYhQCyxbye/AuFx/pAbsz9K+vKL7h1ShUXdN2fz4VUPiyQYRsRqOoVG1DsiCgzd5B6LW0YW77NFpjDQeg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.0.3", + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "micromatch": "^4.0.4", + "node-abort-controller": "^3.1.1", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=18.18" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/metro-file-map/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/metro-file-map/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/metro-minify-terser": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.81.0.tgz", + "integrity": "sha512-U2ramh3W822ZR1nfXgIk+emxsf5eZSg10GbQrT0ZizImK8IZ5BmJY+BHRIkQgHzWFpExOVxC7kWbGL1bZALswA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-resolver": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.81.0.tgz", + "integrity": "sha512-Uu2Q+buHhm571cEwpPek8egMbdSTqmwT/5U7ZVNpK6Z2ElQBBCxd7HmFAslKXa7wgpTO2FAn6MqGeERbAtVDUA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-runtime": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.0.tgz", + "integrity": "sha512-6oYB5HOt37RuGz2eV4A6yhcl+PUTwJYLDlY9vhT+aVjbUWI6MdBCf69vc4f5K5Vpt+yOkjy+2LDwLS0ykWFwYw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-source-map": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.0.tgz", + "integrity": "sha512-TzsVxhH83dyxg4A4+L1nzNO12I7ps5IHLjKGZH3Hrf549eiZivkdjYiq/S5lOB+p2HiQ+Ykcwtmcja95LIC62g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.81.0", + "nullthrows": "^1.1.1", + "ob1": "0.81.0", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.0.tgz", + "integrity": "sha512-C/1rWbNTPYp6yzID8IPuQPpVGzJ2rbWYBATxlvQ9dfK5lVNoxcwz77hjcY8ISLsRRR15hyd/zbjCNKPKeNgE1Q==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.81.0", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "through2": "^2.0.1", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.81.0.tgz", + "integrity": "sha512-uErLAPBvttGCrmGSCa0dNHlOTk3uJFVEVWa5WDg6tQ79PRmuYRwzUgLhVzn/9/kyr75eUX3QWXN79Jvu4txt6Q==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.81.0.tgz", + "integrity": "sha512-HrQ0twiruhKy0yA+9nK5bIe3WQXZcC66PXTvRIos61/EASLAP2DzEmW7IxN/MGsfZegN2UzqL2CG38+mOB45vg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.81.0", + "metro-babel-transformer": "0.81.0", + "metro-cache": "0.81.0", + "metro-cache-key": "0.81.0", + "metro-minify-terser": "0.81.0", + "metro-source-map": "0.81.0", + "metro-transform-plugins": "0.81.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.24.0.tgz", + "integrity": "sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.24.0.tgz", + "integrity": "sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.24.0" + } + }, + "node_modules/metro/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/metro/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "devOptional": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/nocache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.0.tgz", + "integrity": "sha512-6Cvrkxt1tqaRdWqTAMcVYEiO5i1xcF9y7t06nFdjFqkfPsEloCf8WwhXdwBpNUkVYSQlSGS7cDgVQR86miBfBQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pretty-format/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/pretty-format/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.0.tgz", + "integrity": "sha512-sA8gF/pUhjoGAN3s1Ya43h+F4Q0z7cv9RgqbUfhP7bJI0MbqeshLYFb6hiHgZorovGr8AXqhLi22eQ7V3pru/Q==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.77.0.tgz", + "integrity": "sha512-oCgHLGHFIp6F5UbyHSedyUXrZg6/GPe727freGFvlT7BjPJ3K6yvvdlsp7OEXSAHz6Fe7BI2n5cpUyqmP9Zn+Q==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.6.3", + "@react-native/assets-registry": "0.77.0", + "@react-native/codegen": "0.77.0", + "@react-native/community-cli-plugin": "0.77.0", + "@react-native/gradle-plugin": "0.77.0", + "@react-native/js-polyfills": "0.77.0", + "@react-native/normalize-colors": "0.77.0", + "@react-native/virtualized-lists": "0.77.0", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "0.25.1", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "commander": "^12.0.0", + "event-target-shim": "^5.0.1", + "flow-enums-runtime": "^0.0.6", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jest-environment-node": "^29.6.3", + "jsc-android": "^250231.0.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.81.0", + "metro-source-map": "^0.81.0", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.0.1", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.24.0-canary-efb381bbf-20230505", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.3", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^18.2.6", + "react": "^18.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-config": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.3.tgz", + "integrity": "sha512-3D05Abgk5DfDw9w258EzXvX5AkU7eqj3u9H0H0L4gUga4nYg/zuupcrpGbpF4QeXBcJ84jjs6g8JaEP6VBT7Pg==", + "license": "MIT", + "peerDependencies": { + "react-native-windows": ">=0.61" + }, + "peerDependenciesMeta": { + "react-native-windows": { + "optional": true + } + } + }, + "node_modules/react-native-gesture-handler": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.22.1.tgz", + "integrity": "sha512-E0C9D+Ia2UZYevoSV9rTKjhFWEVdR/3l4Z3TUoQrI/wewgzDlmJOrYvGW5aMlPUuQF2vHQOdFfAWhVEqFu4tWw==", + "license": "MIT", + "dependencies": { + "@egjs/hammerjs": "^2.0.17", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-reanimated": { + "version": "3.16.7", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.7.tgz", + "integrity": "sha512-qoUUQOwE1pHlmQ9cXTJ2MX9FQ9eHllopCLiWOkDkp6CER95ZWeXhJCP4cSm6AD4jigL5jHcZf/SkWrg8ttZUsw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-class-properties": "^7.0.0-0", + "@babel/plugin-transform-classes": "^7.0.0-0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-transform-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "@babel/plugin-transform-unicode-regex": "^7.0.0-0", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.1.0.tgz", + "integrity": "sha512-Y4vyJX+0HPJUQNVeIJTj2/UOjbSJcB09OEwirAWDrOZ67Lz5p43AmjxSy8nnZft1rMzoh3rcPuonB6jJyHTfCw==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.5.0.tgz", + "integrity": "sha512-yBWeN5EHNeew9f0ia9VE7JSlUQzCZEwkb87r7A7/Sg41OJHuRKHNRhmdCOiMBUqwwQi3F+b4NZGywjeM/gWMyg==", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-splash-screen": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-native-splash-screen/-/react-native-splash-screen-3.3.0.tgz", + "integrity": "sha512-rGjt6HkoSXxMqH4SQUJ1gnPQlPJV8+J47+4yhgTIan4bVvAwJhEeJH7wWt9hXSdH4+VfwTS0GTaflj1Tw83IhA==", + "license": "MIT", + "peerDependencies": { + "react-native": ">=0.57.0" + } + }, + "node_modules/react-native-svg": { + "version": "15.11.1", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.11.1.tgz", + "integrity": "sha512-Qmwx/yJKt+AHUr4zjxx/Q69qwKtRfr1+uIfFMQoq3WFRhqU76aL9db1DyvPiY632DAsVGba1pHf92OZPkpjrdQ==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-native/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-native/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-test-renderer/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", + "license": "BSD" + }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.24.0-canary-efb381bbf-20230505", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", + "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sudo-prompt": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "devOptional": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/terser": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/front/foodly_application/package.json b/front/foodly_application/package.json new file mode 100644 index 0000000..b78b355 --- /dev/null +++ b/front/foodly_application/package.json @@ -0,0 +1,57 @@ +{ + "name": "foodly", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android --mode=LocalbuildDebug", + "ios": "react-native run-ios --scheme Develop", + "lint": "eslint .", + "start": "react-native start", + "test": "jest", + "ios-build": "react-native bundle --entry-file='index.js' --bundle-output='./ios/main.jsbundle' --dev=false --platform='ios'" + }, + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-regular-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/react-native-fontawesome": "^0.3.2", + "@react-navigation/bottom-tabs": "^7.2.0", + "@react-navigation/native": "^7.0.14", + "@react-navigation/stack": "^7.1.1", + "axios": "^1.7.9", + "react": "18.3.1", + "react-native": "0.77.0", + "react-native-config": "^1.5.3", + "react-native-gesture-handler": "^2.22.1", + "react-native-reanimated": "^3.16.7", + "react-native-safe-area-context": "^5.1.0", + "react-native-screens": "^4.5.0", + "react-native-splash-screen": "^3.3.0", + "react-native-svg": "^15.11.1" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.3", + "@babel/runtime": "^7.25.0", + "@react-native-community/cli": "15.0.1", + "@react-native-community/cli-platform-android": "15.0.1", + "@react-native-community/cli-platform-ios": "15.0.1", + "@react-native/babel-preset": "0.77.0", + "@react-native/eslint-config": "0.77.0", + "@react-native/metro-config": "0.77.0", + "@react-native/typescript-config": "0.77.0", + "@types/jest": "^29.5.13", + "@types/react": "^18.2.6", + "@types/react-native-vector-icons": "^6.4.18", + "@types/react-test-renderer": "^18.0.0", + "eslint": "^8.19.0", + "jest": "^29.6.3", + "prettier": "2.8.8", + "react-test-renderer": "18.3.1", + "typescript": "5.0.4" + }, + "engines": { + "node": ">=18" + } +} diff --git a/front/foodly_application/src/App.tsx b/front/foodly_application/src/App.tsx new file mode 100644 index 0000000..eea3a2c --- /dev/null +++ b/front/foodly_application/src/App.tsx @@ -0,0 +1,42 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * + * @format + */ + +import React from 'react'; +import { + StatusBar, + useColorScheme, +} from 'react-native'; + +import {NavigationContainer} from '@react-navigation/native'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; + +import { + Colors, +} from 'react-native/Libraries/NewAppScreen'; +import TabNavigator from './navigation/TabNavigator'; + +function App(): React.JSX.Element { + const isDarkMode = useColorScheme() === 'dark'; + + const backgroundStyle = { + backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, + }; + + return ( + + + + + + + ); +} + +export default App; diff --git a/front/foodly_application/src/assets/image.png b/front/foodly_application/src/assets/image.png new file mode 100644 index 0000000..eaa105c Binary files /dev/null and b/front/foodly_application/src/assets/image.png differ diff --git a/front/foodly_application/src/components/CategoryIcon.tsx b/front/foodly_application/src/components/CategoryIcon.tsx new file mode 100644 index 0000000..86ce085 --- /dev/null +++ b/front/foodly_application/src/components/CategoryIcon.tsx @@ -0,0 +1,34 @@ +import { + faAppleWhole, + faBreadSlice, + faFireBurner, + faPlateWheat, + faCookieBite, + faMugSaucer, + faFish, + faBowlFood, + faCow, + faJar, + faEgg, + faQuestion, + faCarrot, + IconDefinition +} from "@fortawesome/free-solid-svg-icons"; + +export const getIconForCategory = (name: string): IconDefinition => { + const iconMapping: { [key: string]: IconDefinition } = { + '๊ณผ์ผ': faAppleWhole, + '๊ณผ์ž/๋น™๊ณผ': faCookieBite, + '๊น€์น˜/๋ฐ˜์ฐฌ': faPlateWheat, + '๋ผ๋ฉด/๊ฐ„ํŽธ์‹': faFireBurner, + '๋ฒ ์ด์ปค๋ฆฌ/์žผ': faBreadSlice, + '์ƒ์ˆ˜/์Œ๋ฃŒ/์ฐจ': faMugSaucer, + '์ˆ˜์‚ฐ/๊ฑด์–ด๋ฌผ': faFish, + '์Œ€/์žก๊ณก/๊ฒฌ๊ณผ': faBowlFood, + '์šฐ์œ /์œ ์ œํ’ˆ': faCow, + '์žฅ/์กฐ๋ฏธ๋ฃŒ': faJar, + '์ •์œก/๊ณ„๋ž€': faEgg, + '์ฑ„์†Œ': faCarrot, + }; + return iconMapping[name] || faQuestion; +}; \ No newline at end of file diff --git a/front/foodly_application/src/components/CategoryItem.tsx b/front/foodly_application/src/components/CategoryItem.tsx new file mode 100644 index 0000000..0ff7d3e --- /dev/null +++ b/front/foodly_application/src/components/CategoryItem.tsx @@ -0,0 +1,59 @@ +// components/CategoryItem.tsx +import React from 'react'; +import Config from 'react-native-config'; +import axios from 'axios'; +import { TouchableOpacity, Text, View, Alert } from 'react-native'; +import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; +import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; +import { useNavigation } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { categoryStyles } from '../styles/categoryStyles'; + +// ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ์ •์˜ (CategoryStack ๋‚ด์˜ Product ์Šคํฌ๋ฆฐ) +type CategoryStackParamList = { + // Product ์Šคํฌ๋ฆฐ์œผ๋กœ ์ด๋™ํ•  ๋•Œ ์ƒํ’ˆ ๋ชฉ๋ก๊ณผ ์นดํ…Œ๊ณ ๋ฆฌ๋ช…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. + Product: { products: any; category: { id: string, name: string } }; +}; + +type NavigationProp = StackNavigationProp; + +interface CategoryItemProps { + id: string; + name: string; + icon: IconDefinition; +} + +const CategoryItem: React.FC = ({ id, name, icon }) => { + const navigation = useNavigation(); + + if (!name) { + return ; + } + + const handlePress = async () => { + try { + // ์นดํ…Œ๊ณ ๋ฆฌ ID๋ฅผ ํฌํ•จํ•˜์—ฌ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. + const response = await axios.get(`${Config.BASE_URL}/api/product/categories/${id}`); + + // API๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ƒํ’ˆ ๋ชฉ๋ก ๋ฐ์ดํ„ฐ + const products = response.data; + + console.log('Fetched products for category', id, products); + + // ProductScreen์œผ๋กœ ๋„ค๋น„๊ฒŒ์ดํŠธํ•˜๋ฉด์„œ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ์™€ ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. + navigation.navigate('Product', { products, category: {id: id, name: name} }); + } catch (error) { + console.error('Error fetching products for category', id, error); + Alert.alert('Error', '์ƒํ’ˆ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + }; + + return ( + + + {name} + + ); +}; + +export default CategoryItem; \ No newline at end of file diff --git a/front/foodly_application/src/components/CategoryPage.tsx b/front/foodly_application/src/components/CategoryPage.tsx new file mode 100644 index 0000000..77bca9c --- /dev/null +++ b/front/foodly_application/src/components/CategoryPage.tsx @@ -0,0 +1,61 @@ +// components/CategoryPage.tsx +import React from 'react'; +import { Text, View, StyleSheet, StyleProp, ViewStyle } from 'react-native'; +import CategoryItem from './CategoryItem'; +import { Category } from '../utils/chunkCategories'; + +import styles from '../styles/styles'; +import { categoryStyles } from '../styles/categoryStyles'; + +interface PageProps { + pageData: Category[]; + sizeInfo: { width: number; height: number }; +} + +const CategoryPage: React.FC = ({ pageData, sizeInfo }) => { + const flattenedContainerStyle: StyleProp = StyleSheet.flatten(styles.container); + const containerPaddingTop = (flattenedContainerStyle as any).paddingTop !== undefined + ? (flattenedContainerStyle as any).paddingTop + : (flattenedContainerStyle as any).padding || 0; + const containerPaddingBottom = (flattenedContainerStyle as any).paddingBottom !== undefined + ? (flattenedContainerStyle as any).paddingBottom + : (flattenedContainerStyle as any).padding || 0; + + const containerPaddingVertical = containerPaddingTop + containerPaddingBottom; + + // ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ „์ฒด ๋†’์ด์—์„œ ํŒจ๋”ฉ์„ ๋บ€ ๊ฐ’์„ 3๋“ฑ๋ถ„ํ•˜์—ฌ ๊ฐ ํ–‰์˜ ๋†’์ด๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. + const availableHeight = sizeInfo.height - containerPaddingVertical; + const rowHeight = availableHeight / 3; + + const rows = []; + for (let i = 0; i < 3; i++) { + // ์˜ˆ์‹œ๋กœ ํ•œ ํ–‰์— 2๊ฐœ์˜ ์•„์ดํ…œ์„ ๋„ฃ๋Š” ๊ตฌ์กฐ๋ผ๋ฉด + const rowItems = pageData.slice(i * 2, i * 2 + 2); + rows.push( + + {rowItems.map(category => ( + + ))} + + ); + } + + return ( + + {rows} + + ); +}; + +export default CategoryPage; \ No newline at end of file diff --git a/front/foodly_application/src/components/ProductPage.tsx b/front/foodly_application/src/components/ProductPage.tsx new file mode 100644 index 0000000..b02c949 --- /dev/null +++ b/front/foodly_application/src/components/ProductPage.tsx @@ -0,0 +1,134 @@ +// components/ProductPage.tsx +import React, { useState } from 'react'; +import { + View, + Text, + TouchableOpacity, + Image, + LayoutChangeEvent, +} from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { RootStackParamList } from '../navigation/TabNavigator'; +import { productStyles } from '../styles/productStyles'; + +interface Product { + productId: string; + coupon: string; + delivery: string; + mall: string; + name: string; + price: number; + rating: number; + thumbnailCaption: string; + thumbnailCaptionShort: string; + thumbnailUrl: string; +} + +interface PageProps { + pageData: Product[]; // ํ˜„์žฌ ํŽ˜์ด์ง€์— ํ‘œ์‹œํ•  ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ + screenLength: number; // ํ™”๋ฉด(๋˜๋Š” ์ปจํ…Œ์ด๋„ˆ) ์„ธ๋กœ ๊ธธ์ด +} + +type NavigationProp = StackNavigationProp; + +const ProductPage: React.FC = ({ pageData, screenLength }) => { + const navigation = useNavigation(); + + // ์ฒซ ๋ฒˆ์งธ ์นด๋“œ(์‹ค์ œ ์ƒํ’ˆ) ๋†’์ด๋ฅผ ์ธก์ •ํ•ด์„œ ์ €์žฅ + const [cardHeight, setCardHeight] = useState(null); + + // 3๊ฐœ ์•„์ดํ…œ์ผ ๋•Œ๋งŒ ๊ณ„์‚ฐ์„ ํ†ตํ•ด gap์„ ๊ตฌํ•˜๊ณ , + // ์•„์ดํ…œ์ด 1๊ฐœ๋‚˜ 2๊ฐœ๋ผ๋ฉด gap ๋Œ€์‹  ๊ณ ์ • margin(์˜ˆ: 10) ์‚ฌ์šฉ + const computedGap = (() => { + if (cardHeight && pageData.length === 3) { + // (ํ™”๋ฉด ์„ธ๋กœ ๊ธธ์ด - ์นด๋“œ3๊ฐœ ๋†’์ด) / (๊ฐ„๊ฒฉ 2๊ฐœ) + // ๋ณดํ†ต 3๊ฐœ์˜ ์นด๋“œ๋ฉด ์‚ฌ์ด๊ฐ€ 2๊ตฐ๋ฐ์ด๋ฏ€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ๋‚˜๋ˆ ์คŒ + const gap = (screenLength - 3 * cardHeight) / 2; + return gap > 0 ? gap : 0; + } + // 3๊ฐœ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ๋Š” ๊ณ ์ • margin ์‚ฌ์šฉ + return 10; + })(); + + return ( + + {pageData.map((product, index) => { + const isLast = index === pageData.length - 1; + + // onLayout: ์ฒซ ๋ฒˆ์งธ โ€˜์‹ค์ œ ์ƒํ’ˆโ€™ ์นด๋“œ์—์„œ๋งŒ ๋†’์ด ์ธก์ • + const onCardLayout = (event: LayoutChangeEvent) => { + if (!cardHeight && product.name) { + const { height } = event.nativeEvent.layout; + setCardHeight(height); + } + }; + + // ๋งŒ์•ฝ product.name์ด ์—†์–ด์„œ โ€œ๋นˆ ์•„์ดํ…œโ€์„ ์ฑ„์šฐ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด + // (์ด ๋กœ์ง์ด ํ•„์š” ์—†์œผ์‹œ๋ฉด ์ œ๊ฑฐํ•˜์…”๋„ ๋ฉ๋‹ˆ๋‹ค) + if (!product.name) { + return ( + + ); + } + + // ์‹ค์ œ ์ƒํ’ˆ ์นด๋“œ + return ( + navigation.navigate('ProductDetail', { product })} + onLayout={onCardLayout} + > + + {product.name} + + {product.price.toLocaleString()}์› + + + {product.rating} / 5์  + + + + {product.thumbnailUrl ? ( + // ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋กœ TouchableOpacity๋กœ ๊ฐ์‹ธ ์ด๋ฏธ์ง€ ๋ถ€๋ถ„ ํด๋ฆญ์‹œ ImageDetail ์ด๋™ + + navigation.navigate('ImageDetail', { + thumbnailUrl: product.thumbnailUrl.replace(/\?type=m510$/, ''), + thumbnailCaption: product.thumbnailCaption, + thumbnailCaptionShort: product.thumbnailCaptionShort, + from: undefined, + }) + } + > + + + ) : ( + + )} + + ); + })} + + ); +}; + +export default ProductPage; \ No newline at end of file diff --git a/front/foodly_application/src/navigation/TabNavigator.tsx b/front/foodly_application/src/navigation/TabNavigator.tsx new file mode 100644 index 0000000..d3b3297 --- /dev/null +++ b/front/foodly_application/src/navigation/TabNavigator.tsx @@ -0,0 +1,361 @@ +import React from 'react'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createStackNavigator } from '@react-navigation/stack'; + +import CategoryScreen from '../screens/CategoryScreen'; +import ProductScreen from '../screens/ProductScreen'; +import CartScreen from '../screens/CartScreen'; +import PaymentScreen from '../screens/PaymentScreen'; +import ProductDetailScreen from '../screens/ProductDetailScreen'; +import MypageScreen from '../screens/MypageScreen'; +import ImageDetailScreen from '../screens/ImageDetailScreen'; + +import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; +import { faLayerGroup } from '@fortawesome/free-solid-svg-icons/faLayerGroup'; +import { faSpinner } from '@fortawesome/free-solid-svg-icons/faSpinner'; +import { faList } from '@fortawesome/free-solid-svg-icons/faList'; +import { faCartShopping } from '@fortawesome/free-solid-svg-icons/faCartShopping'; +import { faCreditCard } from '@fortawesome/free-solid-svg-icons/faCreditCard'; +import { faUser } from '@fortawesome/free-solid-svg-icons/faUser'; +import { TouchableOpacity } from 'react-native-gesture-handler'; +import { faArrowLeft } from '@fortawesome/free-solid-svg-icons/faArrowLeft'; + +const Tab = createBottomTabNavigator(); +const Stack = createStackNavigator(); + +type Product = { + productId: string; + categoryId: string; + coupon: string; + delivery: string; + mall: string; + name: string; + price: number; + rating: number; + thumbnailCaption: string; + thumbnailUrl: string; +} + +export type RootStackParamList = { + Category: undefined; + Product: { + products?: Product[]; + category?: { + id: string; + name: string; + } + } | undefined; + ProductDetail: { + product?: { + productId: string; + coupon: string; + delivery: string; + mall: string; + name: string; + price: number; + rating: number; + thumbnailCaption: string; + thumbnailUrl: string; + }, + ImageDetail: { + thumbnailUrl: string; + thumbnailCaption: string; + thumbnailCaptionShort: string; + from: string | undefined; + } + }; + Payment: undefined; + Cart: undefined; + Mypage: undefined; + ImageDetail: { + thumbnailUrl: string; + thumbnailCaption: string; + thumbnailCaptionShort: string; + from: string | undefined; + }; +}; + +const CategoryStack = () => { + return ( + + + ({ + headerShown: true, + title: '์ƒํ’ˆ ๋ชฉ๋ก', + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + ({ + title: '์ƒ์„ธ์ •๋ณด', + headerShown: true, + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + ({ + title: '์ด๋ฏธ์ง€ ์ƒ์„ธ', + headerShown: true, + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + + ); +}; + +const ProductStack = () => { + return ( + + + ({ + title: '์ƒ์„ธ์ •๋ณด', + headerShown: true, + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + ({ + title: '์ด๋ฏธ์ง€ ์ƒ์„ธ', + headerShown: true, + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + + ); +} + +const CartStack = () => { + return ( + + + ({ + title: '์ƒ์„ธ์ •๋ณด', + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + ({ + title: '์ด๋ฏธ์ง€ ์ƒ์„ธ', + headerShown: true, + headerStyle: { + backgroundColor: '#d3e3e9', + }, + headerTitleStyle: { + fontWeight: 'bold', + fontSize: 24, + }, + headerLeft: () => ( + navigation.goBack()} style={{ marginLeft: 16 }}> + + + ), + })} + /> + + ); +} + +const MypageStack = () => { + return ( + + + + ); +} + +const PaymentStack = () => { + return ( + + + + ); +} + + +const TabNavigator = () => { + return ( + ({ + tabBarIcon: ({ color }) => { + let iconName = faSpinner; + if (route.name === '์นดํ…Œ๊ณ ๋ฆฌ') iconName = faLayerGroup; + else if (route.name === '์ƒํ’ˆ') iconName = faList; + else if (route.name === '์žฅ๋ฐ”๊ตฌ๋‹ˆ') iconName = faCartShopping; + else if (route.name === '๊ฒฐ์ œ') iconName = faCreditCard; + else if (route.name === '๋‚ด ์ •๋ณด') iconName = faUser; + return ; + }, + tabBarActiveTintColor: '#007AFF', + tabBarInactiveTintColor: 'gray', + })} + > + + + + + + + ); +}; + +export default TabNavigator; \ No newline at end of file diff --git a/front/foodly_application/src/screens/CartScreen.tsx b/front/foodly_application/src/screens/CartScreen.tsx new file mode 100644 index 0000000..aefac37 --- /dev/null +++ b/front/foodly_application/src/screens/CartScreen.tsx @@ -0,0 +1,188 @@ +// screens/CartScreen.tsx +import React, { useState, useEffect } from 'react'; +import { + SafeAreaView, + View, + Text, + FlatList, + StyleSheet, + LayoutChangeEvent, + TouchableOpacity, +} from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import axios from 'axios'; +import Config from 'react-native-config'; +import { RootStackParamList } from '../navigation/TabNavigator'; +import styles from '../styles/styles'; +import ProductPage from '../components/ProductPage'; + +interface Product { + id: string; + name: string; + price: string; + rating: number; + // API์—์„œ image URL์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด ํƒ€์ž…์„ string์œผ๋กœ ๋ณ€๊ฒฝ ํ›„ ProductPage์—์„œ ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + image: any; +} + +type NavigationProp = StackNavigationProp; + +const ProductScreen: React.FC = () => { + const navigation = useNavigation(); + + // ์‹ค์ œ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” state + const [cartProducts, setCartProducts] = useState([]); + // FlatList์˜ ๋†’์ด๋ฅผ ์ €์žฅํ•˜๋Š” state (ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ์‚ฌ์šฉ) + const [flatListHeight, setFlatListHeight] = useState(0); + + /** + * ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ, ๋จผ์ € ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  + * ๊ฐ ํ•ญ๋ชฉ์˜ productId๋ฅผ ์ด์šฉํ•ด ์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. + */ + useEffect(() => { + const fetchCartAndProducts = async () => { + try { + // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. + const cartResponse = await axios.get(`${Config.BASE_URL}/api/user/1/cart`); + const cartItems = cartResponse.data; // ์˜ˆ: [{ cartId, userId, productId, productName, quantity, addedAt }, ...] + + // ๊ฐ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด productId๋ฅผ ์ด์šฉํ•ด ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. + const productPromises = cartItems.map(async (cartItem: any) => { + const productResponse = await axios.get( + `${Config.BASE_URL}/api/product/${cartItem.productId}` + ); + // productResponse.data๊ฐ€ Product ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋งž๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. + return productResponse.data; + }); + + const products: Product[] = await Promise.all(productPromises); + setCartProducts(products); + } catch (error) { + console.error('Error fetching cart or product data:', error); + } + }; + + fetchCartAndProducts(); + }, []); + + /** + * FlatList์˜ ๋†’์ด๋ฅผ ์ธก์ •ํ•˜์—ฌ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ •ํ™•ํ•œ ๋†’์ด๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•จ + */ + const handleLayout = (event: LayoutChangeEvent) => { + const { height } = event.nativeEvent.layout; + setFlatListHeight(height); + }; + + /** + * ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ 3๊ฐœ์”ฉ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ถ„ํ• ํ•˜๋Š” ํ•จ์ˆ˜ + */ + const chunkProducts = (products: Product[], size: number): Product[][] => { + const chunks: Product[][] = []; + for (let i = 0; i < products.length; i += size) { + const chunk = products.slice(i, i + size); + // ๋นˆ ์•„์ดํ…œ ์ถ”๊ฐ€: ํ™”๋ฉด ์ฑ„์›€ ์šฉ๋„ + while (chunk.length < size) { + chunk.push({ + productId: `empty-${chunk.length}`, + categoryId: '', + name: '', + price: '0', + rating: 0, + thumbnailUrl: '', + thumbnailCaption: '', + coupon: '', + delivery: '', + mall: '', + }); + } + chunks.push(chunk); + } + return chunks; + }; + + // ๊ฐ€์ ธ์˜จ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ 3๊ฐœ์”ฉ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค. + const pages = chunkProducts(cartProducts, 3); + + return ( + + + {/* ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ */} + + {flatListHeight > 0 && ( + `page-${index}`} + renderItem={({ item }) => ( + + )} + pagingEnabled + decelerationRate="fast" + showsVerticalScrollIndicator={false} + initialNumToRender={pages.length} + /> + )} + + + {/* "์“ธ์–ด๋‚ด๋ ค ๋” ๋ณด๊ธฐ" ํ…์ŠคํŠธ */} + ์“ธ์–ด๋‚ด๋ ค ๋” ๋ณด๊ธฐ + + {/* ๊ฒฐ์ œ ์˜ˆ์ƒ ๊ธˆ์•ก ๋ฒ„ํŠผ */} + + ๊ฒฐ์ œ ์˜ˆ์ƒ ๊ธˆ์•ก + + + {/* ๊ฒฐ์ œํ•˜๊ธฐ ๋ฒ„ํŠผ */} + navigation.navigate('๊ฒฐ์ œ')} + > + ๊ฒฐ์ œํ•˜๊ธฐ + + + + ); +}; + +export default ProductScreen; + +const screenStyles = StyleSheet.create({ + flatListContainer: { + flex: 1, + }, + moreText: { + textAlign: 'center', + color: '#666', + marginTop: 16, + fontSize: 16, + }, + paymentButton: { + backgroundColor: '#fff1c9', + paddingVertical: 8, + paddingHorizontal: 12, + borderRadius: 8, + marginTop: 16, + height: 64, + justifyContent: 'center', + }, + payButton: { + backgroundColor: '#0f5975', + paddingVertical: 8, + paddingHorizontal: 12, + borderRadius: 8, + height: 64, + justifyContent: 'center', + }, + priceText: { + color: '#000', + fontSize: 24, + textAlign: 'center', + fontWeight: 'bold', + }, + buttonText: { + color: '#fff', + fontSize: 24, + textAlign: 'center', + fontWeight: 'bold', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/screens/CategoryScreen.tsx b/front/foodly_application/src/screens/CategoryScreen.tsx new file mode 100644 index 0000000..451d60b --- /dev/null +++ b/front/foodly_application/src/screens/CategoryScreen.tsx @@ -0,0 +1,167 @@ +// screens/CategoryScreen.tsx +import React, { useState, useEffect } from 'react'; +import { + Text, + View, + TextInput, + FlatList, + LayoutChangeEvent, + TouchableOpacity +} from 'react-native'; +import axios from 'axios'; +import Config from 'react-native-config'; +import CategoryPage from '../components/CategoryPage'; +import { chunkCategories, Category } from '../utils/chunkCategories'; +// ๋งŒ์•ฝ ์ œํ’ˆ์šฉ chunk ํ•จ์ˆ˜๊ฐ€ ๋ณ„๋„๋กœ ํ•„์š”ํ•˜๋‹ค๋ฉด chunkProducts๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ utils์— ๋”ฐ๋กœ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. + +import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; +import { getIconForCategory } from '../components/CategoryIcon'; + +import styles from '../styles/styles'; + +// โ–ผ ์ƒˆ๋กœ ์ถ”๊ฐ€ (ProductPage import) +import ProductPage from '../components/ProductPage'; + +const CategoryScreen: React.FC = () => { + const [categories, setCategories] = useState([]); + const [flatListSize, setFlatListSize] = useState({ width: 0, height: 0 }); + + // ๊ฒ€์ƒ‰์–ด ์ƒํƒœ + const [searchTerm, setSearchTerm] = useState(''); + // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ƒํƒœ (์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ๋ผ ๊ฐ€์ •) + const [searchResults, setSearchResults] = useState([]); + // ๊ฒ€์ƒ‰ ๋ชจ๋“œ ์—ฌ๋ถ€ + const [isSearching, setIsSearching] = useState(false); + + // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ ๋ฐฑ์—”๋“œ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ด + useEffect(() => { + axios + .get(`${Config.BASE_URL}/api/category`) + .then(response => { + // response.data๋Š” CategoryResponseDTO ๋ฐฐ์—ด์ด๋ผ๊ณ  ๊ฐ€์ • + const fetchedCategories: Category[] = response.data.map((cat: any) => ({ + id: cat.categoryId.toString(), // id๋ฅผ string์œผ๋กœ ๋ณ€ํ™˜ (ํ•„์š”์— ๋”ฐ๋ผ) + name: cat.name, + icon: getIconForCategory(cat.name), + })); + setCategories(fetchedCategories); + }) + .catch(error => { + console.error('Error fetching categories:', error); + }); + }, []); + + // "๊ฒ€์ƒ‰" ์•„์ด์ฝ˜์„ ๋ˆŒ๋ €์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜ + const handleSearch = () => { + // ๊ฒ€์ƒ‰์–ด๊ฐ€ ์—†์œผ๋ฉด ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋ฆฌํ„ด + if (!searchTerm.trim()) { + setIsSearching(false); + setSearchResults([]); + return; + } + + setIsSearching(true); + + axios + .get(`${Config.BASE_URL}/api/product/search`, { + // ๋ฐฑ์—”๋“œ API์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด ์˜ˆ: `name`์ด๋ผ๊ณ  ๊ฐ€์ • + params: { name: searchTerm }, + }) + .then(response => { + console.log('Search results:', response.data); + setSearchResults(response.data); // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์ƒํƒœ์— ์ €์žฅ + }) + .catch(error => { + console.error('Error searching products:', error); + }); + }; + + // ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐฐ์—ด์„ chunkCategories ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ถ„ํ•  + const pages = chunkCategories(categories, 6); + + // โ–ผ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋„ 3๊ฐœ์”ฉ ๋Š์–ด์„œ ProductPage์—์„œ ํ‘œ์‹œ (์ƒํ’ˆ์ด 3๊ฐœ ๋‹จ์œ„๋ผ๊ณ  ๊ฐ€์ •) + // ๋งŒ์•ฝ ProductPage๊ฐ€ 3๊ฐœ๊ฐ€ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๊ฐœ์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค๋ฉด ํ•ด๋‹น ์ˆ˜์น˜ ์กฐ์ • + const chunkSearchResults = (data: any[], size: number) => { + const result = []; + for (let i = 0; i < data.length; i += size) { + result.push(data.slice(i, i + size)); + } + return result; + }; + + const searchPages = chunkSearchResults(searchResults, 3); + + // FlatList ์˜์—ญ์˜ ํฌ๊ธฐ๋ฅผ ์ธก์ •ํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜ + const handleLayout = (event: LayoutChangeEvent) => { + const { width, height } = event.nativeEvent.layout; + setFlatListSize({ width, height }); + }; + + return ( + + {/* ๊ฒ€์ƒ‰์ฐฝ */} + + + {/* TouchableOpacity๋กœ ์•„์ด์ฝ˜์„ ๊ฐ์‹ธ ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ */} + + + + + + {/* + ๊ฒ€์ƒ‰ ์ค‘(isSearching=true)์ด๋ผ๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œ, + ์•„๋‹ˆ๋ผ๋ฉด ๊ธฐ์กด ์นดํ…Œ๊ณ ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œ + */} + {isSearching ? ( + // โ–ผ ProductPage ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œ + `search-page-${index}`} + renderItem={({ item }) => ( + + )} + // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ „์ฒด๋ฅผ ์„ธ๋กœ ์Šคํฌ๋กค๋กœ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด + // pagingEnabled={false} ๋กœ ๋‘๊ณ , decelerationRate="fast"๋„ ์ œ๊ฑฐ/์ทจํ–ฅ๋Œ€๋กœ ์„ค์ • + pagingEnabled + decelerationRate="fast" + style={{ flex: 1, marginVertical: 12}} + onLayout={handleLayout} + /> + ) : ( + <> + {/* ํŽ˜์ด์ง€ ๋‹จ์œ„ ์Šค์™€์ดํ”„(์Šคํฌ๋กค) ์˜์—ญ */} + `page-${index}`} + renderItem={({ item }) => ( + + )} + pagingEnabled + decelerationRate="fast" + showsVerticalScrollIndicator={false} + style={{ flex: 1 }} + onLayout={handleLayout} + /> + + {/* "๋” ๋ณด๊ธฐ" ์•ˆ๋‚ด ํ…์ŠคํŠธ */} + ์“ธ์–ด๋‚ด๋ ค ๋” ๋ณด๊ธฐ + + )} + + ); +}; + +export default CategoryScreen; \ No newline at end of file diff --git a/front/foodly_application/src/screens/ImageDetailScreen.tsx b/front/foodly_application/src/screens/ImageDetailScreen.tsx new file mode 100644 index 0000000..4147279 --- /dev/null +++ b/front/foodly_application/src/screens/ImageDetailScreen.tsx @@ -0,0 +1,59 @@ +// screens/ImageDetailScreen.tsx +import React, { useLayoutEffect } from 'react'; +import { View, Text, Image, StyleSheet, SafeAreaView } from 'react-native'; +import { StackScreenProps } from '@react-navigation/stack'; +import { RootStackParamList } from '../navigation/TabNavigator'; + +type ImageDetailScreenProps = StackScreenProps; + +const ImageDetailScreen: React.FC = ({ route, navigation }) => { + const { thumbnailUrl, thumbnailCaption, thumbnailCaptionShort, from } = route.params; + + const caption = () => { + if (from === 'ProductDetail') { + console.log("from ProductDetail", thumbnailCaption); + return thumbnailCaption; + } + console.log("not from ProductDetail", thumbnailCaptionShort); + return thumbnailCaptionShort; + } + + useLayoutEffect(() => { + navigation.setOptions({ + title: from === 'ProductDetail' ? 'ํฌ์žฅ ์„ค๋ช…' : '์ œํ’ˆ ์ด๋ฏธ์ง€ ์†Œ๊ฐœ', + }); + }, [navigation, from]); + + return ( + + + {caption()} + + ); +}; + +export default ImageDetailScreen; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + justifyContent: 'center', + alignItems: 'center', + }, + image: { + width: 300, + height: 300, + resizeMode: 'contain', + }, + caption: { + marginTop: 16, + fontSize: 20, + marginHorizontal: 16, + textAlign: 'center', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/screens/MypageScreen.tsx b/front/foodly_application/src/screens/MypageScreen.tsx new file mode 100644 index 0000000..5badae4 --- /dev/null +++ b/front/foodly_application/src/screens/MypageScreen.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native'; + +import styles from '../styles/styles'; +import { mypageStyles } from '../styles/mypageStyles'; + +const MyPageScreen: React.FC = () => { + return ( + + {/* Profile Section */} + + + ์˜ค์ˆ˜ํ˜„ ๋‹˜ + + + {/* Info Update Buttons */} + ์ •๋ณด ์ˆ˜์ • + + ๋ฐฐ์†ก์ง€ ์ˆ˜์ • + + + ๊ฒฐ์ œ์ •๋ณด ์ˆ˜์ • + + + {/* Logout Button */} + + ๋กœ๊ทธ์•„์›ƒ + + + ); +}; + +export default MyPageScreen; \ No newline at end of file diff --git a/front/foodly_application/src/screens/PaymentScreen.tsx b/front/foodly_application/src/screens/PaymentScreen.tsx new file mode 100644 index 0000000..6572084 --- /dev/null +++ b/front/foodly_application/src/screens/PaymentScreen.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { View, Text, FlatList, StyleSheet } from 'react-native'; + +import styles from '../styles/styles'; +import { paymentStyles } from '../styles/paymentStyles'; + +const paymentData = [ + { + id: '1', + date: '2025-02-01', + description: '์ƒ์ฃผ๊ณถ๊ฐ... ์™ธ 5', + amount: '1,212,220์›', + }, + { + id: '2', + date: '2025-02-01', + description: '์ƒ์ฃผ๊ณถ๊ฐ... ์™ธ 5', + amount: '1,212,220์›', + }, +]; + +const PaymentScreen: React.FC = () => { + const renderItem = ({ item }) => ( + + + {item.date} + {item.description} + + {item.amount} + + ); + + return ( + + {/* Payment History List */} + item.id} /> + + ); +}; + +export default PaymentScreen; diff --git a/front/foodly_application/src/screens/ProductDetailScreen.tsx b/front/foodly_application/src/screens/ProductDetailScreen.tsx new file mode 100644 index 0000000..0fe1042 --- /dev/null +++ b/front/foodly_application/src/screens/ProductDetailScreen.tsx @@ -0,0 +1,604 @@ +// ProductDetailScreen.tsx +import React, { useRef, useState, useEffect } from 'react'; +import Config from 'react-native-config'; +import { + View, + Text, + TouchableOpacity, + Animated, + StyleSheet, + LayoutAnimation, + Platform, + UIManager, + Dimensions, + Image, // ์ด๋ฏธ์ง€ ์‚ฌ์šฉ +} from 'react-native'; +import { useRoute, RouteProp, useNavigation } from '@react-navigation/native'; +import { RootStackParamList } from '../navigation/TabNavigator'; +import { productDetailStyles } from '../styles/productDetailStyles'; +import axios from 'axios'; // axios ์ถ”๊ฐ€ + +if ( + Platform.OS === 'android' && + UIManager.setLayoutAnimationEnabledExperimental +) { + UIManager.setLayoutAnimationEnabledExperimental(true); +} + +// ===================================== +// ํƒ€์ž… ์ •์˜(์„ ํƒ์‚ฌํ•ญ) +// ===================================== +interface DescriptionResponseDTO { + productId: number; + summaryExp: string; + summaryCook: string; + summaryStore: string; + cautionAllergy1: string; + cautionAllergy2: string; + cautionStore: string; + sizeDescription: string; + sizeImageUrl: string; + nutrition: string; + ingredient: string; + reviewGoodTaste: string; + reviewGoodTasteNum: number; + reviewGoodDelivery: string; + reviewGoodDeliveryNum: number; + reviewBadTaste: string; + reviewBadTasteNum: number; + reviewBadDelivery: string; + reviewBadDeliveryNum: number; +} + +// ===================================== +// ์ƒ์ˆ˜ ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ณ„์‚ฐ์šฉ ๋ณ€์ˆ˜ +// ===================================== +type RouteProps = RouteProp; + +const HEADER_MAX_HEIGHT = 260; +const HEADER_MIN_HEIGHT = 80; +const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; + +// ๊ธฐ๊ธฐ ๋„ˆ๋น„ +const SCREEN_WIDTH = Dimensions.get('window').width; + +// ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๋ฐ ์œ„์น˜ +const imageInitialSize = 220; +const imageFinalSize = 128; +const imageInitialLeft = (SCREEN_WIDTH - imageInitialSize) / 2; +const imageFinalLeft = SCREEN_WIDTH - imageFinalSize - 8; +const imageTranslateXOutput = imageFinalLeft - imageInitialLeft; // ์˜ค๋ฅธ์ชฝ ์ด๋™๋Ÿ‰ + +// ํ…์ŠคํŠธ ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ณธ ๊ฐ’ +const textContainerMargin = 16; +const textContainerWidth = SCREEN_WIDTH - 2 * textContainerMargin; +const textInitialLeft = textContainerMargin; // ์ดˆ๊ธฐ ์ขŒ์ธก ์—ฌ๋ฐฑ 16 +const textTranslateYOutput = 106 - imageInitialSize; + +// ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ • +const animatedNameFont = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [28, 20], + extrapolate: 'clamp', + }); + +const animatedInfoFont = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [20, 20], + extrapolate: 'clamp', + }); + +const animatedProductNameBottomMargin = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE * 0.5, HEADER_SCROLL_DISTANCE], + outputRange: [12, 9, 6], + extrapolate: 'clamp', + }); + +const animatedPriceBottomMargin = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE * 0.5, HEADER_SCROLL_DISTANCE], + outputRange: [8, 4, 0], + extrapolate: 'clamp', + }); + +const textTranslateY = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [0, textTranslateYOutput - 28], + extrapolate: 'clamp', + }); + +// ํ…์ŠคํŠธ ์ปจํ…Œ์ด๋„ˆ์˜ width ์• ๋‹ˆ๋ฉ”์ด์…˜ (์ดˆ๊ธฐ: textContainerWidth, ์ตœ์ข…: 70% ์ •๋„) +const animatedTextContainerWidth = (scrollY: Animated.Value) => + scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [textContainerWidth, textContainerWidth * 0.6], + extrapolate: 'clamp', + }); + +const ProductDetailScreen: React.FC = ({ route }) => { + const navigation = useNavigation(); + const { product } = route.params; + const [isScrolled, setIsScrolled] = useState(false); + + // ์Šคํฌ๋กค ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’ + const scrollY = useRef(new Animated.Value(0)).current; + + // ===================================== + // ์ƒํ’ˆ ์ƒ์„ธ ๋‚ด์šฉ(Description) ๋กœ๋”ฉ + // ===================================== + const [description, setDescription] = useState(null); + + useEffect(() => { + axios + .get(`${Config.BASE_URL}/api/descriptions/${product?.productId}`) + .then(res => { + console.log(res.data); + setDescription(res.data); + }) + .catch(err => { + console.error(err); + }); + }, [product?.productId]); + + // ===================================== + // ์•„์ฝ”๋””์–ธ์— ๋ณด์—ฌ์ค„ ๋ฒ„ํŠผ/์ปจํ…์ธ  ๊ตฌ์„ฑ + // ===================================== + const ACCORDION_ITEMS = [ + // 1) ์ƒํ’ˆ ์„ค๋ช… (์ƒํ’ˆ ์„ค๋ช… + ์กฐ๋ฆฌ ๋ฐฉ๋ฒ•) + { id: 1, title: '์ƒํ’ˆ ์„ค๋ช…' }, + // 2) ์ฃผ์˜์‚ฌํ•ญ (1์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ, 2์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ, ๋ณด๊ด€ ์œ ์˜์‚ฌํ•ญ) + { id: 4, title: '์ฃผ์˜์‚ฌํ•ญ' }, + // 3) ํฌ๊ธฐ ์ •๋ณด (์ด๋ฏธ์ง€ + size ํ…์ŠคํŠธ) + { id: 5, title: 'ํฌ๊ธฐ ์ •๋ณด' }, + // 4) ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด (์˜์–‘ ์ •๋ณด + ์„ฑ๋ถ„ ์ •๋ณด) + { id: 6, title: '์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด' }, + // 5) ๋ฆฌ๋ทฐ ์š”์•ฝ (๋†’์€ ๋ฆฌ๋ทฐ ์š”์•ฝ + ๋‚ฎ์€ ๋ฆฌ๋ทฐ ์š”์•ฝ) + { id: 8, title: '๋ฆฌ๋ทฐ ์š”์•ฝ' }, + ]; + + // ์Šคํฌ๋กค ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ + useEffect(() => { + const listener = scrollY.addListener(({ value }) => { + value > 0 ? setIsScrolled(true) : setIsScrolled(false); + }); + return () => { + scrollY.removeListener(listener); + }; + }, []); + + // ํ—ค๋” ๋†’์ด ์• ๋‹ˆ๋ฉ”์ด์…˜ + const headerHeight = scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT], + extrapolate: 'clamp', + }); + + // ์ด๋ฏธ์ง€ ์• ๋‹ˆ๋ฉ”์ด์…˜ + const imageTranslateX = scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [0, imageTranslateXOutput], + extrapolate: 'clamp', + }); + const imageSizeAnim = scrollY.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [imageInitialSize, imageFinalSize], + extrapolate: 'clamp', + }); + + // ์•„์ฝ”๋””์–ธ ํ™•์žฅ ์—ฌ๋ถ€ + const [expandedSection, setExpandedSection] = useState(null); + const toggleSection = (id: number) => { + LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); + setExpandedSection(prev => (prev === id ? null : id)); + }; + + // ===================================== + // ๊ฐ ์•„์ฝ”๋””์–ธ ์•„์ดํ…œ๋ณ„ ์ปค์Šคํ…€ ์ปจํ…์ธ  ๋ Œ๋”๋ง + // ===================================== + + // id=1: ์ƒํ’ˆ ์„ค๋ช… + ์กฐ๋ฆฌ ๋ฐฉ๋ฒ• + const renderItem1Content = () => { + return ( + + ์ƒํ’ˆ ์„ค๋ช… + + {description?.summaryExp || '์ƒํ’ˆ ์„ค๋ช… ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'} + + + {/* ์กฐ๋ฆฌ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๋•Œ๋งŒ */} + {description?.summaryCook && ( + <> + ์กฐ๋ฆฌ ๋ฐฉ๋ฒ• + + {description?.summaryCook || '์กฐ๋ฆฌ ๋ฐฉ๋ฒ• ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'} + + + )} + + ); + }; + + // id=4: ์ฃผ์˜์‚ฌํ•ญ (1์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ, 2์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ, ๋ณด๊ด€ ์œ ์˜์‚ฌํ•ญ) + const renderItem4Content = () => { + return ( + + 1์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ + + {description?.cautionAllergy1 ?? '์œ ๋ฐœ ์„ฑ๋ถ„์ด ์—†์Šต๋‹ˆ๋‹ค.'} + + + 2์ฐจ ์•Œ๋ ˆ๋ฅด๊ธฐ + + {description?.cautionAllergy2 ?? '์œ ๋ฐœ ์„ฑ๋ถ„์ด ์—†์Šต๋‹ˆ๋‹ค.'} + + + ๋ณด๊ด€ ์œ ์˜์‚ฌํ•ญ + + {description?.cautionStore ?? '์—†์Šต๋‹ˆ๋‹ค.'} + + + ); + }; + + // id=5: ํฌ๊ธฐ ์ •๋ณด (์ด๋ฏธ์ง€ + size ํ…์ŠคํŠธ) + const renderItem5Content = () => { + return ( + + {/* ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ ํ‘œ์‹œ (์—†๋‹ค๋ฉด ๊ธฐ๋ณธ ํ…์ŠคํŠธ ๋Œ€์ฒด ๊ฐ€๋Šฅ) */} + {description?.sizeImageUrl ? ( + + ) : ( + + ์ด๋ฏธ์ง€ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. + + )} + + {/* ํฌ๊ธฐ ์ •๋ณด */} + + {description?.sizeDescription || 'ํฌ๊ธฐ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'} + + + ); + }; + + // id=6: ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด (์˜์–‘ ์ •๋ณด + ์„ฑ๋ถ„ ์ •๋ณด) + const renderItem6Content = () => { + return ( + + ์˜์–‘ ์ •๋ณด + + {description?.nutrition || '์˜์–‘ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'} + + + ์„ฑ๋ถ„ ์ •๋ณด + + {description?.ingredient || '์„ฑ๋ถ„ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'} + + + ); + }; + + // id=8: ๋ฆฌ๋ทฐ ์š”์•ฝ (๋†’์€ ๋ฆฌ๋ทฐ ์š”์•ฝ + ๋‚ฎ์€ ๋ฆฌ๋ทฐ ์š”์•ฝ) + const renderItem8Content = () => { + if (!description?.reviewGoodTasteNum) { + return ( + + + ๋ฆฌ๋ทฐ ์š”์•ฝ ์ •๋ณด๋Š” ํ˜„์žฌ ์ค€๋น„์ค‘์ž…๋‹ˆ๋‹ค. + + + ) + } + + return ( + + {/* ๋†’์€ ๋ฆฌ๋ทฐ ์š”์•ฝ */} + + ๋†’์€ ๋ฆฌ๋ทฐ ์š”์•ฝ + + {/* ๋ง› */} + + ๋ง› ({description?.reviewGoodTasteNum ?? 0}๊ฐœ) + + + {description?.reviewGoodTaste || '-'} + + {/* ๋ฐฐ์†ก */} + + ๋ฐฐ์†ก ({description?.reviewGoodDeliveryNum ?? 0}๊ฐœ) + + + {description?.reviewGoodDelivery || '-'} + + + {/* ๋‚ฎ์€ ๋ฆฌ๋ทฐ ์š”์•ฝ */} + + ๋‚ฎ์€ ๋ฆฌ๋ทฐ ์š”์•ฝ + + {/* ๋ง› */} + + ๋ง› ({description?.reviewBadTasteNum ?? 0}๊ฐœ) + + + {description?.reviewBadTaste || '-'} + + {/* ๋ฐฐ์†ก */} + + ๋ฐฐ์†ก ({description?.reviewBadDeliveryNum ?? 0}๊ฐœ) + + + {description?.reviewBadDelivery || '-'} + + + ); + }; + + // ์•„์ฝ”๋””์–ธ ๊ณตํ†ต ๋ Œ๋”๋ง ํ•จ์ˆ˜ + const renderAccordionContent = (itemId: number) => { + switch (itemId) { + case 1: + return renderItem1Content(); + case 4: + return renderItem4Content(); + case 5: + return renderItem5Content(); + case 6: + return renderItem6Content(); + case 8: + return renderItem8Content(); + default: + return ํ•ด๋‹น ์„น์…˜ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.; + } + }; + + return ( + + {/* ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ—ค๋” */} + + {/* ์ด๋ฏธ์ง€ ์˜์—ญ */} + + navigation.navigate('ImageDetail', { + thumbnailUrl: product?.thumbnailUrl, + thumbnailCaption: product?.thumbnailCaption, + thumbnailCaptionShort: product?.thumbnailCaptionShort, + from: 'ProductDetail', + }) + } + > + + + + + + {/* ํ…์ŠคํŠธ ์˜์—ญ */} + + {/* ์ œํ’ˆ๋ช… */} + + {product?.name} + + + {/* ๊ฐ€๊ฒฉ ์ •๋ณด */} + + + ์ด๋งˆํŠธ๋ชฐ + + + {!isScrolled && ( + + {(product?.price * 1.2).toLocaleString()}์›์—์„œ + + )} + + {product?.price.toLocaleString()}์› + + + + + {/* ๋ณ„์  ์ •๋ณด (์˜ˆ์‹œ๋กœ ๊ณ ์ • ๊ฐ’) */} + + + {product.rating} / 5์  + + + ๊ฑด์˜ ๋ฆฌ๋ทฐ + + + + + + {/* ์Šคํฌ๋กค ์˜์—ญ */} + + + {/* ํ• ์ธ ๋ฒ„ํŠผ */} + + + {product?.coupon} + + + + {/* ๋ฐฐ์†ก ๋ฒ„ํŠผ */} + + + {product?.delivery} + + + + {/* ์•„์ฝ”๋””์–ธ ๋ฒ„ํŠผ๋“ค */} + + {ACCORDION_ITEMS.map(item => { + const isExpanded = expandedSection === item.id; + return ( + + toggleSection(item.id)} + > + + {item.title} + + + {isExpanded && ( + + {renderAccordionContent(item.id)} + + )} + + ); + })} + + + {/* ํ•˜๋‹จ ์—ฌ๋ฐฑ (๊ณ ์ • ๋ฒ„ํŠผ์ด ๊ฐ€๋ฆฌ์ง€ ์•Š๋„๋ก) */} + + + + + {/* ํ•˜๋‹จ ๊ณ ์ • ๋ฒ„ํŠผ */} + + console.log('์žฅ๋ฐ”๊ตฌ๋‹ˆ ํด๋ฆญ')} + > + ์žฅ๋ฐ”๊ตฌ๋‹ˆ + + + navigation.navigate('๊ฒฐ์ œ')} + > + ๊ตฌ๋งค + + + + ); +}; + +export default ProductDetailScreen; + + +// ================== ๋กœ์ปฌ ์Šคํƒ€์ผ ================== +const localStyles = StyleSheet.create({ + headerContainer: { + backgroundColor: '#fff', + }, + accordionButton: { + backgroundColor: '#FFF1C9', + height: 60, + padding: 12, + borderRadius: 8, + justifyContent: 'center', + }, + accordionButtonText: { + fontSize: 24, + fontWeight: 'bold', + alignSelf: 'center', + }, + accordionContent: { + backgroundColor: '#FFF9E7', + padding: 12, + borderRadius: 8, + }, + // ๊ธฐ๋ณธ ํ…์ŠคํŠธ + accordionContentText: { + fontSize: 20, + lineHeight: 24, + marginTop: 8, + marginBottom: 8, + }, + // ๋Œ€์ œ๋ชฉ + bigHeadline: { + fontSize: 22, + fontWeight: 'bold', + marginTop: 8, + marginBottom: 4, + }, + // ์ผ๋ฐ˜ ๋‹จ๋ฝ + paragraph: { + fontSize: 18, + lineHeight: 24, + marginBottom: 12, + }, + // ํšŒ์ƒ‰ ํ—ค๋” + greyHeaderContainer: { + backgroundColor: '#d9d9d9', + paddingVertical: 8, + borderRadius: 8, + marginBottom: 8, + justifyContent: 'center', + alignItems: 'center', + }, + greyHeaderText: { + fontSize: 22, + fontWeight: 'bold', + textAlign: 'center', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/screens/ProductScreen.tsx b/front/foodly_application/src/screens/ProductScreen.tsx new file mode 100644 index 0000000..6d435ef --- /dev/null +++ b/front/foodly_application/src/screens/ProductScreen.tsx @@ -0,0 +1,314 @@ +// screens/ProductScreen.tsx +import React, { useState, useEffect } from 'react'; +import { + SafeAreaView, + View, + Text, + TextInput, + FlatList, + LayoutChangeEvent, + TouchableOpacity, +} from 'react-native'; +import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; +import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons'; +import axios from 'axios'; + +import ProductPage from '../components/ProductPage'; +import styles from '../styles/styles'; +import { productStyles } from '../styles/productStyles'; +import { StackScreenProps } from '@react-navigation/stack'; +import { RootStackParamList } from '../navigation/TabNavigator'; +import Config from 'react-native-config'; + +// ์ƒํ’ˆ ๋ฐ์ดํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค +export interface Product { + productId: string; + categoryId: string; + coupon: string; + delivery: string; + mall: string; + name: string; + price: number; + rating: number; + thumbnailCaption: string; + thumbnailUrl: string; +} + +// ํ•„ํ„ฐ ๋ฐ์ดํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค +export interface Filter { + id: string; + aspect: string; +} + +// ๋žญํฌ ์กฐํšŒ API์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค +export interface ProductRankResponse { + productRankId: number; + productId: number; + aspectId: number; + categoryId: number; + productRank: number; +} + +// fallback์šฉ ๋”๋ฏธ ์ƒํ’ˆ ๋ชฉ๋ก (ํ•„์š”์‹œ ์‚ฌ์šฉ) +const dummyProducts: Product[] = [ + { + productId: '1', + categoryId: '1', + name: '์ƒํ’ˆ๋ช…', + price: 1360, + rating: 4.87, + thumbnailUrl: '../assets/image.png', + thumbnailCaption: '์ƒํ’ˆ ์„ค๋ช…', + coupon: '์ฟ ํฐ ์„ค๋ช…', + delivery: '๋ฐฐ์†ก ์„ค๋ช…', + mall: 'ํŒ๋งค์ ', + }, +]; + +type ProductScreenProps = StackScreenProps; + +const ProductScreen: React.FC = ({ route }) => { + // FlatList์˜ ๋†’์ด (ํŽ˜์ด์ง€ ๋‹จ์œ„ ์Šคํฌ๋กค์— ์‚ฌ์šฉ) + const [flatListHeight, setFlatListHeight] = useState(0); + // ํ•„ํ„ฐ ๊ด€๋ จ ์ƒํƒœ + const [filters, setFilters] = useState([]); + const [products, setProducts] = useState([]); + const [originalProducts, setOriginalProducts] = useState([]); + const [activeFilterId, setActiveFilterId] = useState(null); + + // โ˜… ๊ฒ€์ƒ‰ ๊ด€๋ จ ์ƒํƒœ ์ถ”๊ฐ€ + const [searchTerm, setSearchTerm] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [isSearching, setIsSearching] = useState(false); + + // ์ „๋‹ฌ๋ฐ›์€ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์šฐ์„  ์‚ฌ์šฉ + const passedProducts = route.params?.products; + + // ์ดˆ๊ธฐ ์ƒํ’ˆ ๋ชฉ๋ก ์„ค์ • (์ „๋‹ฌ๋ฐ›์€ ๋ฐ์ดํ„ฐ ๋˜๋Š” API ํ˜ธ์ถœ) + useEffect(() => { + if (passedProducts && passedProducts.length > 0) { + setProducts(passedProducts); + setOriginalProducts(passedProducts); + } else { + axios.get(`${Config.BASE_URL}/api/product`) + .then(response => { + const data: Product[] = response.data; + if (Array.isArray(data) && data.length > 0) { + setProducts(data); + setOriginalProducts(data); + } else { + setProducts(dummyProducts); + setOriginalProducts(dummyProducts); + } + }) + .catch(error => { + console.error('์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error); + setProducts(dummyProducts); + setOriginalProducts(dummyProducts); + }); + } + }, [passedProducts]); + + /** + * FlatList์˜ ๋†’์ด๋ฅผ ์ธก์ •ํ•˜์—ฌ ๊ฐ ํŽ˜์ด์ง€์˜ ๋†’์ด๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. + */ + const handleLayout = (event: LayoutChangeEvent) => { + const { height } = event.nativeEvent.layout; + setFlatListHeight(height); + }; + + /** + * ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ 3๊ฐœ์”ฉ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ถ„ํ• ํ•˜๋Š” ํ•จ์ˆ˜ + * (๋นˆ ์•„์ดํ…œ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•œ ํŽ˜์ด์ง€๋ฅผ ํ•ญ์ƒ 3๊ฐœ๋กœ ๋งž์ถค) + */ + const chunkProducts = (data: Product[], size: number): Product[][] => { + const chunks: Product[][] = []; + for (let i = 0; i < data.length; i += size) { + const chunk = data.slice(i, i + size); + // ํ™”๋ฉด์„ ์ฑ„์šฐ๊ธฐ ์œ„ํ•ด ๋นˆ ์•„์ดํ…œ ์ถ”๊ฐ€ (ํ•„์š” ์‹œ) + while (chunk.length < size) { + chunk.push({ + productId: `empty-${chunk.length}`, + categoryId: '', + name: '', + price: 0, + rating: 0, + thumbnailUrl: '', + thumbnailCaption: '', + coupon: '', + delivery: '', + mall: '', + }); + } + chunks.push(chunk); + } + return chunks; + }; + + // ๊ธฐ๋ณธ ์ƒํ’ˆ ๋ชฉ๋ก๊ณผ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ 3๊ฐœ์”ฉ ๋ถ„ํ•  + const pages = chunkProducts(products, 3); + const searchPages = chunkProducts(searchResults, 3); + + // categoryId๋Š” route.params์—์„œ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค๊ณ  ๊ฐ€์ • (ํ•„์š”์‹œ ์ˆ˜์ •) + const categoryId = route.params?.category?.id; + + // ํ•„ํ„ฐ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์˜ˆ: ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ•„ํ„ฐ) + useEffect(() => { + const fetchFilters = async () => { + if (!categoryId) return; + try { + const response = await axios.get( + `${Config.BASE_URL}/api/category/${categoryId}/aspects` + ); + const data: Filter[] = response.data; + setFilters(Array.isArray(data) && data.length > 0 ? data : []); + } catch (error) { + console.error('ํ•„ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error); + setFilters([]); + } + }; + fetchFilters(); + }, [categoryId]); + + /** + * ํ•„ํ„ฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ + */ + const handleFilterPress = async (filter: Filter) => { + // ์ด๋ฏธ ํ™œ์„ฑํ™”๋œ ํ•„ํ„ฐ๋ฅผ ๋ˆ„๋ฅธ ๊ฒฝ์šฐ ํ•ด์ œ + if (activeFilterId === filter.id) { + setActiveFilterId(null); + setProducts(originalProducts); + return; + } + + try { + setActiveFilterId(filter.id); + const aspectId = parseInt(filter.id, 10); + + // 1. ๋žญํฌ ๋ฐ์ดํ„ฐ ์กฐํšŒ + const rankResponse = await axios.get( + `${Config.BASE_URL}/api/rank/aspect/${aspectId}` + ); + const rankList: ProductRankResponse[] = rankResponse.data; + console.log('rankList', rankList); + + // 2. ๊ฐ productId๋ฅผ ํ†ตํ•ด ๊ฐœ๋ณ„ ์ƒํ’ˆ ์กฐํšŒ + const productPromises = rankList.map(rank => + axios.get(`${Config.BASE_URL}/api/product/${rank.productId}`) + ); + const productResponses = await Promise.all(productPromises); + const sortedProducts: Product[] = productResponses.map(response => response.data); + + setProducts(sortedProducts); + } catch (error) { + console.error('ํ•„ํ„ฐ ์ •๋ ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error); + } + }; + + /** + * ๊ฒ€์ƒ‰ ํ•จ์ˆ˜: ๊ฒ€์ƒ‰์–ด๊ฐ€ ์žˆ์œผ๋ฉด ๊ฒ€์ƒ‰ API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค. + */ + const handleSearch = () => { + if (!searchTerm.trim()) { + // ๊ฒ€์ƒ‰์–ด๊ฐ€ ์—†์œผ๋ฉด ๊ฒ€์ƒ‰ ๋ชจ๋“œ๋ฅผ ํ•ด์ œํ•˜๊ณ  ์›๋ž˜ ๋ชฉ๋ก์„ ์‚ฌ์šฉ + setIsSearching(false); + setSearchResults([]); + return; + } + setIsSearching(true); + axios + .get(`${Config.BASE_URL}/api/product/search`, { + params: { name: searchTerm }, + }) + .then(response => { + console.log('Search results:', response.data); + setSearchResults(response.data); + }) + .catch(error => { + console.error('Error searching products:', error); + }); + }; + + return ( + + + {/* ๊ฒ€์ƒ‰์ฐฝ */} + + + + + + + + {/* ๊ฒ€์ƒ‰ ๋ชจ๋“œ๊ฐ€ ์•„๋‹ ๋•Œ๋งŒ ํ•„ํ„ฐ ๋ฒ„ํŠผ ํ‘œ์‹œ */} + {!isSearching && filters.length > 0 && ( + `filter-${item.id}`} + horizontal + showsHorizontalScrollIndicator={false} + style={productStyles.filterScroll} + renderItem={({ item }) => { + const isActive = activeFilterId === item.id; + return ( + handleFilterPress(item)} + > + + {item.aspect} + + + ); + }} + /> + )} + + {/* ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ ๋˜๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ (ํ•œ ํŽ˜์ด์ง€์— 3๊ฐœ์”ฉ, ์Šคํฌ๋กค๋กœ ํŽ˜์ด์ง€ ์ด๋™) */} + + {flatListHeight > 0 && ( + + isSearching ? `search-page-${index}` : `page-${index}` + } + renderItem={({ item }) => ( + + )} + pagingEnabled + decelerationRate="fast" + showsVerticalScrollIndicator={false} + // ์ดˆ๊ธฐ ๋ Œ๋”๋งํ•  ํŽ˜์ด์ง€ ์ˆ˜ (ํ•„์š”์— ๋”ฐ๋ผ ์กฐ์ •) + initialNumToRender={isSearching ? searchPages.length : pages.length} + /> + )} + + + {/* "๋” ๋ณด๊ธฐ" ์•ˆ๋‚ด ํ…์ŠคํŠธ */} + ์“ธ์–ด๋‚ด๋ ค ๋” ๋ณด๊ธฐ + + + ); +}; + +export default ProductScreen; \ No newline at end of file diff --git a/front/foodly_application/src/styles/categoryStyles.ts b/front/foodly_application/src/styles/categoryStyles.ts new file mode 100644 index 0000000..dc4ca66 --- /dev/null +++ b/front/foodly_application/src/styles/categoryStyles.ts @@ -0,0 +1,37 @@ +import { StyleSheet } from 'react-native'; + +export const categoryStyles = StyleSheet.create({ + rowContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + flex: 1, + }, + itemContainer: { + flex: 1, // ํ–‰ ๋‚ด์—์„œ ๋™์ผํ•œ ๊ณต๊ฐ„์„ ์ฐจ์ง€ + margin: 8, // ํ•ญ๋ชฉ ๊ฐ„ ๊ฐ„๊ฒฉ + padding: 20, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: '#fff1c9', + borderRadius: 8, + }, + itemIcon: { + marginBottom: 12, + }, + emptyItem: { + flex: 1, + margin: 8, + padding: 20, + backgroundColor: 'transparent', + borderRadius: 8, + }, + icon: { + fontSize: 32, + marginBottom: 8, + }, + name: { + fontSize: 32, + fontWeight: 'bold', + textAlign: 'center', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/styles/mypageStyles.ts b/front/foodly_application/src/styles/mypageStyles.ts new file mode 100644 index 0000000..235f8d6 --- /dev/null +++ b/front/foodly_application/src/styles/mypageStyles.ts @@ -0,0 +1,55 @@ +import { StyleSheet } from 'react-native'; + +export const mypageStyles = StyleSheet.create({ + profileContainer: { + display: 'flex', + flexDirection: 'row', + marginBottom: 20, + borderRadius: 8, + }, + profileImage: { + width: 150, + height: 150, + marginBottom: 10, + }, + userName: { + marginTop: 20, + marginLeft: 20, + fontSize: 28, + fontWeight: 'bold', + }, + bigTitle: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 10, + }, + infoButton: { + backgroundColor: '#FFECB3', + height: 60, + marginVertical: 5, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + }, + buttonText: { + fontSize: 24, + fontWeight: 'bold', + }, + logoutButton: { + backgroundColor: '#D32F2F', + height: 60, + marginTop: 20, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + position: 'absolute', + bottom: 12, + left: 12, + right: 12, + }, + logoutText: { + fontSize: 24, + fontWeight: 'bold', + color: '#FFFFFF', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/styles/paymentStyles.ts b/front/foodly_application/src/styles/paymentStyles.ts new file mode 100644 index 0000000..a0d90b2 --- /dev/null +++ b/front/foodly_application/src/styles/paymentStyles.ts @@ -0,0 +1,22 @@ +import { StyleSheet } from 'react-native'; + +export const paymentStyles = StyleSheet.create({ + itemContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + padding: 16, + }, + date: { + fontSize: 24, + fontWeight: 'bold', + }, + amount: { + fontSize: 24, + fontWeight: 'bold', + color: '#005A82', + }, + description: { + fontSize: 24, + color: '#555', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/styles/productDetailStyles.ts b/front/foodly_application/src/styles/productDetailStyles.ts new file mode 100644 index 0000000..f1e95aa --- /dev/null +++ b/front/foodly_application/src/styles/productDetailStyles.ts @@ -0,0 +1,133 @@ +import { StyleSheet } from 'react-native'; + +export const productDetailStyles = StyleSheet.create({ + image: { + width: 220, + height: 220, + resizeMode: 'contain', + borderRadius: 8, + marginBottom: 16, + alignSelf: 'center', + }, + placeholderImage: { + width: 200, + height: 200, + backgroundColor: '#ddd', + borderRadius: 8, + marginBottom: 16, + }, + name: { + fontSize: 28, + fontWeight: 'bold', + marginBottom: 12, + }, + mallpriceContainer: { + marginHorizontal: 4, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginBottom: 8, + }, + mall: { + fontSize: 16, + color: '#7f8c8d', + }, + priceContainer: { + display: 'flex', + flexDirection: 'row', + alignItems: 'baseline' + }, + beforePrice: { + fontSize: 16, + fontWeight: 'bold', + color: '#7f8c8d', + textDecorationLine: 'line-through', + marginRight: 8, + }, + market: { + fontSize: 16, + color: '#7f8c8d', + textAlign: 'center', + }, + price: { + fontSize: 24, + fontWeight: 'bold', + color: '#2c3e50', + textAlign: 'center', + }, + discountButton: { + backgroundColor: '#CD4747', + height: 48, + borderRadius: 8, + display: 'flex', + justifyContent: 'center', + }, + discount: { + fontSize: 24, + color: 'white', + fontWeight: 'bold', + textAlign: 'center', + }, + deliveryButton: { + backgroundColor: '#FFD040', + height: 48, + borderRadius: 8, + display: 'flex', + justifyContent: 'center', + }, + delivery: { + fontSize: 24, + fontWeight: 'bold', + textAlign: 'center', + }, + ratingContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + marginHorizontal: 4, + }, + rating: { + fontSize: 24, + textAlign: 'center', + marginVertical: 4, + }, + buttonContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + marginTop: 20, + }, + cartButton: { + flex: 1, + backgroundColor: '#4DAED2', + height: 64, + padding: 12, + marginRight: 8, + borderRadius: 8, + alignItems: 'center', + justifyContent: 'center', + }, + buyButton: { + flex: 1, + backgroundColor: '#0F5975', + height: 64, + padding: 12, + borderRadius: 8, + alignItems: 'center', + justifyContent: 'center', + }, + buttonText: { + color: '#fff', + fontSize: 28, + fontWeight: 'bold', + }, + bottomFixedContainer: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + flexDirection: 'row', + backgroundColor: '#fff', + padding: 8, + marginHorizontal: 12, + justifyContent: 'space-between', + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/styles/productStyles.ts b/front/foodly_application/src/styles/productStyles.ts new file mode 100644 index 0000000..980260c --- /dev/null +++ b/front/foodly_application/src/styles/productStyles.ts @@ -0,0 +1,72 @@ +import { StyleSheet } from 'react-native'; + +export const productStyles = StyleSheet.create({ + pageContainer: { + flex: 1, + justifyContent: 'space-between', + paddingHorizontal: 4, + }, + filterScroll: { + maxHeight: 44, + }, + filterButton: { + backgroundColor: '#f0f0f0', + paddingVertical: 8, + paddingHorizontal: 12, + borderRadius: 24, + marginRight: 10, + justifyContent: 'center', + }, + filterText: { + fontSize: 24, + fontWeight: 'bold', + color: '#333', + }, + flatListContainer: { + flex: 1, + marginTop: 20, + }, + productInfo: { + flex: 2, + }, + productCard: { + flex: 1, // ๊ฐ ์ƒํ’ˆ์ด 1/3 ๋†’์ด๋ฅผ ์ฐจ์ง€ + flexDirection: 'row', + borderRadius: 8, + minHeight: 160, + }, + productName: { + fontSize: 24, + fontWeight: 'bold', + marginTop: 4, + marginBottom: 4, + paddingRight: 8, + }, + productPrice: { + fontSize: 24, + fontWeight: 'bold', + color: '#0F5975', + }, + productRating: { + fontSize: 24, + color: '#888', + }, + productImage: { + width: 148, + height: 148, + resizeMode: 'contain', + borderRadius: 8, + }, + placeholderImage: { + flex: 1, + width: 80, + height: 80, + backgroundColor: '#ddd', + borderRadius: 8, + }, + emptyItem: { + flex: 1, + marginVertical: 5, + backgroundColor: 'transparent', + } +}); \ No newline at end of file diff --git a/front/foodly_application/src/styles/styles.ts b/front/foodly_application/src/styles/styles.ts new file mode 100644 index 0000000..0f4ec9f --- /dev/null +++ b/front/foodly_application/src/styles/styles.ts @@ -0,0 +1,48 @@ +import { StyleSheet } from 'react-native'; + +export default StyleSheet.create({ + // container + container: { + flex: 1, + backgroundColor: '#fff', + padding: 12, + }, + safeContainer: { + flex: 1, + backgroundColor: '#F0F8FF', + }, + title: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 16, + }, + + // search + searchContainer: { + flexDirection: 'row', + alignItems: 'center', + borderColor: '#CCCCCC', + borderWidth: 1, + borderRadius: 64, + paddingHorizontal: 8, + paddingVertical: 4, + marginBottom: 16, + }, + searchIcon: { + marginRight: 8, + }, + searchInput: { + flex: 1, + height: 40, + marginLeft: 8, + fontSize: 16, + }, + + // slide to see more + moreText: { + textAlign: 'center', + color: '#666', + marginTop: 16, + fontSize: 16, + }, +}); \ No newline at end of file diff --git a/front/foodly_application/src/utils/chunkCategories.ts b/front/foodly_application/src/utils/chunkCategories.ts new file mode 100644 index 0000000..c98805e --- /dev/null +++ b/front/foodly_application/src/utils/chunkCategories.ts @@ -0,0 +1,25 @@ +import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; +import { faQuestion } from "@fortawesome/free-solid-svg-icons"; + +// utils/chunkCategories.ts +export interface Category { + id: string; + name: string; + icon: IconDefinition; + } + + /** + * categories ๋ฐฐ์—ด์„ size(6)๋งŒํผ ์ž˜๋ผ 2์ฐจ์› ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + * ๋งˆ์ง€๋ง‰ ๋ฉ์–ด๋ฆฌ๊ฐ€ 6๊ฐœ๋ณด๋‹ค ์ž‘์œผ๋ฉด ๋นˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜์—ฌ 6๊ฐœ๋กœ ๋งž์ถฅ๋‹ˆ๋‹ค. + */ + export const chunkCategories = (categories: Category[], size: number): Category[][] => { + const chunks: Category[][] = []; + for (let i = 0; i < categories.length; i += size) { + const chunk = categories.slice(i, i + size); + while (chunk.length < size) { + chunk.push({ id: `empty-${chunk.length}`, name: '', icon: faQuestion }); + } + chunks.push(chunk); + } + return chunks; + }; \ No newline at end of file diff --git a/front/foodly_application/tsconfig.json b/front/foodly_application/tsconfig.json new file mode 100644 index 0000000..304ab4e --- /dev/null +++ b/front/foodly_application/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@react-native/typescript-config/tsconfig.json" +} diff --git a/models/final_outputs/.gitkeep b/models/final_outputs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/.gitkeep b/models/nutrition_ingredients_information/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/README.md b/models/nutrition_ingredients_information/README.md new file mode 100644 index 0000000..e39dba5 --- /dev/null +++ b/models/nutrition_ingredients_information/README.md @@ -0,0 +1,138 @@ +# ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด ์ถ”์ถœ +> ๋ณธ ๊ธฐ๋Šฅ์€ OCR์„ ํ™œ์šฉํ•˜์—ฌ ์ œํ’ˆ์˜ ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. +> ํŒ๋งค์ž๊ฐ€ ์ œ๊ณตํ•œ ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด ์ด๋ฏธ์ง€๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์˜์–‘์ •๋ณด, ์›์žฌ๋ฃŒ, ์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ/2์ฐจ), ๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „/ํ›„) ๋“ฑ์„ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค. +> ์ด๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ์žฅ์• ์ธ๋„ ์ œํ’ˆ์˜ ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. + + +## ์ฃผ์š” ํŠน์ง• +1. **OCR ๊ธฐ๋ฐ˜ ์„ฑ๋ถ„ ์ •๋ณด ์ถ”์ถœ**: Clova OCR์„ ํ™œ์šฉํ•˜์—ฌ ์ œํ’ˆ ์ด๋ฏธ์ง€์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์ •์ œํ•ฉ๋‹ˆ๋‹ค. +2. **HCX ๋ชจ๋ธ Fine-tuning**: GPT-4o๋ฅผ ์‚ฌ์šฉํ•ด ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ HCX-003 ๋ชจ๋ธ์„ ํŒŒ์ธํŠœ๋‹ํ•ฉ๋‹ˆ๋‹ค. +3. **HCX ๋ชจ๋ธ์„ ํ†ตํ•œ ์„ฑ๋ถ„ ์ •๋ณด ์ถ”๋ก **: Fine-tuned HCX ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ OCR ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ž๋™ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. +4. **Rule-based vs HCX ๊ฒฐ๊ณผ ๋น„๊ต**: Rule-based ๋ฐฉ์‹์˜ ๊ฒฐ๊ณผ์™€ HCX ์ถ”๋ก  ๊ฒฐ๊ณผ์˜ ์ผ์น˜๋„๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. +5. **์ž๋™ํ™”๋œ ์„ฑ๋ถ„ ๋ถ„์„ ํŒŒ์ดํ”„๋ผ์ธ**: Object Detection โ†’ OCR โ†’ HCX ์ถ”๋ก  โ†’ ๋น„๊ต ๋ถ„์„๊นŒ์ง€ ์ „ ๊ณผ์ •์ด ์ž๋™ํ™”๋œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. + + +## ํด๋” ๊ตฌ์กฐ +```bash +. +โ”œโ”€โ”€ README.md +โ”œโ”€โ”€ main.py # ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ฝ”๋“œ +โ”œโ”€โ”€ environment.yml # Conda ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ +โ”œโ”€โ”€ config +โ”‚ โ””โ”€โ”€ config.yaml # YOLO ํ•™์Šต ๋ฐ ์ถ”๋ก  ๊ด€๋ จ ์„ค์ • ํŒŒ์ผ +โ”œโ”€โ”€ data +โ”‚ โ”œโ”€โ”€ HCX # HyperClovaX ๊ด€๋ จ ํ•™์Šต, ์ถ”๋ก , ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ +โ”‚ โ”‚ โ”œโ”€โ”€ eval +โ”‚ โ”‚ โ”œโ”€โ”€ inference +โ”‚ โ”‚ โ””โ”€โ”€ train +โ”‚ โ”œโ”€โ”€ OCR # CLOVA OCR ๊ด€๋ จ ์ถ”๋ก  ๋ฐ์ดํ„ฐ์…‹ +โ”‚ โ”‚ โ””โ”€โ”€ inference +โ”‚ โ”œโ”€โ”€ preprocessed # ์ „์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ์…‹ ์ €์žฅ ํด๋” +โ”‚ โ”œโ”€โ”€ Rule-based # ๊ทœ์น™ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์˜ ์ถ”๋ก  ๋ฐ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ +โ”‚ โ”‚ โ”œโ”€โ”€ eval +โ”‚ โ”‚ โ””โ”€โ”€ inference +โ”‚ โ””โ”€โ”€ YOLO # YOLO ๊ด€๋ จ ํ•™์Šต, ์ถ”๋ก , ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ์…‹ +โ”‚ โ”œโ”€โ”€ inference +โ”‚ โ”œโ”€โ”€ output +โ”‚ โ””โ”€โ”€ train +โ”œโ”€โ”€ prompt +โ”‚ โ”œโ”€โ”€ system_prompt_vf.txt # ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ +โ”‚ โ””โ”€โ”€ user_prompt_vf.txt # ์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ +โ”œโ”€โ”€ src +โ”‚ โ”œโ”€โ”€ HCX +โ”‚ โ”‚ โ”œโ”€โ”€ 01_HCX_dataset.py # HCX ๋ฐ์ดํ„ฐ์…‹ ๋กœ๋”ฉ ๋ฐ ์ฒ˜๋ฆฌ +โ”‚ โ”‚ โ”œโ”€โ”€ 02_HCX_train.py # HCX ๋ชจ๋ธ ํ•™์Šต ์ฝ”๋“œ +โ”‚ โ”‚ โ”œโ”€โ”€ 03_HCX_inference.py # HCX ๋ชจ๋ธ ์ถ”๋ก  ์ฝ”๋“œ +โ”‚ โ”‚ โ”œโ”€โ”€ 04_post_processing.py # HCX ์ถ”๋ก  ํ›„์ฒ˜๋ฆฌ ์ฝ”๋“œ +โ”‚ โ”‚ โ””โ”€โ”€ 05_eval_ingredient.py # ์„ฑ๋ถ„ ์ •๋ณด ํ‰๊ฐ€ ์ฝ”๋“œ +โ”‚ โ”œโ”€โ”€ OCR +โ”‚ โ”‚ โ”œโ”€โ”€ 01_OCR_text.py # OCR ํ…์ŠคํŠธ ์ถ”์ถœ ์ฝ”๋“œ +โ”‚ โ”‚ โ”œโ”€โ”€ 02_OCR_row_col_323.py # OCR ํ‘œ ํ˜•์‹ ์ถ”์ถœ ์ฝ”๋“œ (์ „์ฒด ๋ฐ์ดํ„ฐ์…‹) +โ”‚ โ”‚ โ””โ”€โ”€ 03_OCR_row_col_273_50.py # OCR ํ‘œ ํ˜•์‹ ์ถ”์ถœ ์ฝ”๋“œ (ํ•™์Šต ๋ฐ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹) +โ”‚ โ”œโ”€โ”€ preprocessing +โ”‚ โ”‚ โ”œโ”€โ”€ 01_data_selection_323.py # ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด ์ด๋ฏธ์ง€ ์„ ํƒ ์ฝ”๋“œ (์ „์ฒด ๋ฐ์ดํ„ฐ์…‹) +โ”‚ โ”‚ โ””โ”€โ”€ 02_data_selection_273.py # ์˜์–‘/์„ฑ๋ถ„ ์ •๋ณด ์ด๋ฏธ์ง€ ์„ ํƒ ์ฝ”๋“œ (ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹) +โ”‚ โ”œโ”€โ”€ Rule-based +โ”‚ โ”‚ โ”œโ”€โ”€ 01_rule_based.py # ๊ทœ์น™ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์œผ๋กœ ์ •๋ณด ์ถ”์ถœ +โ”‚ โ”‚ โ””โ”€โ”€ 02_eval_nutrition.py # ์˜์–‘ ์ •๋ณด ํ‰๊ฐ€ ์ฝ”๋“œ +โ”‚ โ””โ”€โ”€ YOLO +โ”‚ โ”‚ โ”œโ”€โ”€ 01_data_conversion.py # ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ์ฝ”๋“œ +โ”‚ โ”‚ โ””โ”€โ”€ 02_YOLO.py # YOLO ๋ชจ๋ธ ํ•™์Šต ๋ฐ ์ถ”๋ก  ์ฝ”๋“œ +โ””โ”€โ”€ utils + โ””โ”€โ”€ utils.py # ingredient ๊ด€๋ จ ํ•™์Šต ๋ฐ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ์ฒ˜๋ฆฌ ์ฝ”๋“œ +``` + + +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• +### 1) ํ™˜๊ฒฝ ๊ตฌ์ถ• +- Python 3.10.15 ๋ฒ„์ „ ๊ถŒ์žฅ +- ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜ +```bash +conda env create -f environment.yml +``` + + +### 2) ์‹คํ–‰ +- ๊ธฐ๋ณธ ์‹คํ–‰ +```bash +python main.py +``` + + +## Input & Output +### 1. Input: +- `data/OCR/inference/images_323_OCR_row_col.csv`, `data/OCR/inference/images_50_OCR_row_col.csv`: OCR ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ +- `data/HCX/train/finetuning_273_gpt_human_v2.csv`, `data/preprocessed/images_50.csv`: Fine-tuning ํ•™์Šต ๋ฐ์ดํ„ฐ +- `data/HCX/eval/images_50_ingredient_processed.csv`, `data/HCX/inference/images_323_ingredient.csv`: ์„ฑ๋ถ„ ์ •์ œ ๋ฐ ๋น„๊ต ๋ฐ์ดํ„ฐ +- `prompt/*`: ์‹œ์Šคํ…œ ๋ฐ ์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ +- Clova Studio API ํ‚ค ๋ฐ Task ID + +### 2. Output +- `data/HCX/train/HCX_train_v2.csv`: GPT-4o๋กœ ์ƒ์„ฑํ•œ ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ +- `data/HCX/eval/finetuning_50_gpt.csv`: ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ +- `data/HCX/inference/HCX_inference_v2.csv`: Fine-tuned ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ +- `data/HCX/inference/images_323_ingredient.csv`: HCX ์ถ”๋ก  ๊ฒฐ๊ณผ ์„ฑ๋ถ„ ์ •๋ณด + + + + +## ์ฝ”๋“œ ์„ค๋ช… +- `main.py` + - config/config.yaml ์„ค์ • ํŒŒ์ผ์„ ์ฝ๊ณ , ์„ ํƒํ•œ ํŒŒ์ดํ”„๋ผ์ธ์˜ Python ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ๊ด€๋ฆฌ ๋„๊ตฌ +- `src/HCX/01_HCX_dataset.py` + - OCR ๊ฒฐ๊ณผ(ocr_data)๋ฅผ user_prompt_vf.txt ํ…œํ”Œ๋ฆฟ์— ์‚ฝ์ž…ํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ •์ œ๋œ GPT ๋ชจ๋ธ์˜ ์‘๋‹ต(reference)๊ณผ ํ•จ๊ป˜ ์ƒˆ๋กœ์šด ํ•™์Šต ๋ฐ์ดํ„ฐ(HCX_train_v2.csv)๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ๋Š” C_ID, T_ID, Text(ํ”„๋กฌํ”„ํŠธ), Completion(๋ชจ๋ธ ์‘๋‹ต) ํ˜•์‹์œผ๋กœ ์ €์žฅ +- `src/HCX/02_HCX_train.py` + - Clova Studio API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HCX-003 ๋ชจ๋ธ์˜ ํ•™์Šต(Task)์„ ์ƒ์„ฑํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋กœ, ์ฃผ์–ด์ง„ API ํ‚ค์™€ ์š”์ฒญ ID๋ฅผ ์‚ฌ์šฉํ•ด HCX_train_v2.csv ๋ฐ์ดํ„ฐ๋ฅผ ํ•™์Šต ์š”์ฒญ์œผ๋กœ ์ „์†ก + - ์š”์ฒญ์ด ์„ฑ๊ณตํ•˜๋ฉด status ์ฝ”๋“œ 20000์„ ํ™•์ธํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ +- `src/HCX/03_HCX_inference.py` + - OCR ๊ฒฐ๊ณผ(images_323_OCR_row_col.csv)๋ฅผ ํ™œ์šฉํ•˜์—ฌ Clova Studio์˜ Fine-tuned ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ HCX_inference_v2.csv์— ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ์š”์ฒญ ์‹คํŒจ ์‹œ ์ตœ๋Œ€ 20ํšŒ ์žฌ์‹œ๋„ํ•˜๋ฉฐ, system_prompt_vf.txt ๋ฐ user_prompt_vf.txt ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ API ์š”์ฒญ์„ ์ƒ์„ฑ +- `src/HCX/04_post_processing.py` + - HCX ๋ชจ๋ธ์˜ ์ถ”๋ก  ๊ฒฐ๊ณผ(HCX_inference_v2.csv)์—์„œ JSON ํ˜•์‹์˜ ์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ •์ œ ๋ฐ ํŒŒ์‹ฑํ•˜์—ฌ ๊ฐœ๋ณ„ ์ปฌ๋Ÿผ(์›์žฌ๋ฃŒ, ์•Œ๋ ˆ๋ฅด๊ธฐ, ๋ณด๊ด€๋ฐฉ๋ฒ• ๋“ฑ)์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , images_323_ingredient.csv๋กœ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - img-ID์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์ •๋ ฌํ•œ ํ›„ ๋ถˆํ•„์š”ํ•œ ์ปฌ๋Ÿผ์„ ์ œ๊ฑฐํ•˜๊ณ  ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅ +- `src/HCX/05_eval_ingredient.py` + - OCR ๊ธฐ๋ฐ˜์œผ๋กœ ์ถ”์ถœ๋œ ์„ฑ๋ถ„ ์ •๋ณด(images_50_ingredient_processed.csv)์™€ HCX ๋ชจ๋ธ ์ถ”๋ก  ๊ฒฐ๊ณผ(images_323_ingredient.csv)๋ฅผ img-ID ๊ธฐ์ค€์œผ๋กœ ๋น„๊ตํ•˜์—ฌ Levenshtein ๊ฑฐ๋ฆฌ ๋ฐ ์œ ์‚ฌ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ๊ฐ ์„ฑ๋ถ„ ํ•ญ๋ชฉ(์›์žฌ๋ฃŒ, ์•Œ๋ ˆ๋ฅด๊ธฐ, ๋ณด๊ด€๋ฐฉ๋ฒ• ๋“ฑ)์˜ ํ‰๊ท  ์œ ์‚ฌ๋„๋ฅผ ์ถœ๋ ฅํ•˜์—ฌ ๋‘ ๋ฐ์ดํ„ฐ์˜ ์ผ์น˜๋„๋ฅผ ํ‰๊ฐ€ +- `src/OCR/01_OCR_text.py` + - ์ด ์ฝ”๋“œ๋Š” YOLO ํƒ์ง€๋œ ๊ฐ์ฒด์˜ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ํฌ๋กญํ•œ ํ›„, Clova OCR API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ CSV ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ํฌ๋กญํ•œ ์ด๋ฏธ์ง€๋“ค์€ ์ž„์‹œ ํด๋”(temp_crop)์—์„œ ์ฒ˜๋ฆฌ ํ›„ ์‚ญ์ œ๋˜๋ฉฐ, OCR ๊ฒฐ๊ณผ๋Š” | ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ €์žฅ +- `src/OCR/02_OCR_row_col_323.py` + - YOLO ํƒ์ง€๋œ ๊ฐ์ฒด ์˜์—ญ์„ ํฌ๋กญํ•œ ํ›„, Clova OCR์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ”๊ณผ ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœ ๋ฐ ์ •๋ฆฌํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ €์žฅํ•œ ํ›„, CSV ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - OCR ๊ฒฐ๊ณผ๋Š” ํ–‰(row), ์—ด(col) ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ํ‚ค๋กœ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ์ •๋ฆฌ +- `src/OCR/03_OCR_row_col_273_50.py` + - ์ด๋ฏธ์ง€ ID(img-ID)๋ฅผ ๊ธฐ์ค€์œผ๋กœ images_323_OCR_row_col.csv์—์„œ images_273.csv์™€ images_50.csv์— ํฌํ•จ๋œ ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋งํ•˜์—ฌ ๊ฐ๊ฐ ์ƒˆ๋กœ์šด CSV ํŒŒ์ผ(images_273_OCR_row_col.csv, images_50_OCR_row_col.csv)๋กœ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ +- `src/Rule-based/01_rule_based.py` + - OCR ๊ฒฐ๊ณผ์—์„œ ์˜์–‘์„ฑ๋ถ„ ์ •๋ณด๋ฅผ ์ •๊ทœ์‹์„ ํ™œ์šฉํ•ด ์ถ”์ถœํ•œ ํ›„, images_323_nutrition.csv๋กœ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - img-ID์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์ •๋ ฌํ•œ ํ›„, ํ•„์š” ์—†๋Š” ์ปฌ๋Ÿผ์„ ์ œ๊ฑฐํ•˜๊ณ  ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅ +- `src/Rule-based/02_eval_nutrition.py` + - OCR์—์„œ ์ถ”์ถœํ•œ ์˜์–‘์ •๋ณด(images_323_nutrition.csv)์™€ ์ •๋‹ต ๋ฐ์ดํ„ฐ(total_nutrition.csv)๋ฅผ ID๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ตํ•˜์—ฌ ๊ฐ ์˜์–‘์„ฑ๋ถ„๋ณ„ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ๋ถ„์„ํ•˜๊ณ , ์ „์ฒด ๋ฐ ๊ฐœ๋ณ„ ํ•ญ๋ชฉ์˜ ์ผ์น˜ ํ™•๋ฅ ์„ ๊ณ„์‚ฐํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ +- `src/YOLO/01_data_conversion.py` + - CSV ํŒŒ์ผ์—์„œ ์ด๋ฏธ์ง€ URL๊ณผ ID๋ฅผ ์ฝ์–ด์™€, ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ์ง€์ •๋œ ํด๋”(YOLO/inference/images, YOLO/train/images)์— ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…์€ img-ID ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์ œ๊ฑฐํ•œ ํ›„ .png ํ™•์žฅ์ž๋กœ ์ €์žฅ +- `src/YOLO/02_YOLO.py` + - ์ด ์ฝ”๋“œ๋Š” YOLO ๋ชจ๋ธ(yolo11n.pt)์„ ๋กœ๋“œํ•˜์—ฌ ํ•™์Šตํ•˜๊ณ , ์ง€์ •๋œ ํด๋”์˜ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๊ฐ์ฒด ํƒ์ง€๋ฅผ ์ˆ˜ํ–‰ํ•œ ํ›„ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ํƒ์ง€๋œ ๊ฐ์ฒด ์ •๋ณด๋ฅผ YOLO ํ˜•์‹์˜ ๋ผ๋ฒจ(txt) ํŒŒ์ผ๋กœ ์ €์žฅ +- `utils/utils.py` + - OCR ๋ฐ์ดํ„ฐ์™€ ํ•™์Šต ๋ฐ์ดํ„ฐ(finetuning_273_gpt_human_v2.csv)๋ฅผ ๋ณ‘ํ•ฉ ๋ฐ ํ›„์ฒ˜๋ฆฌํ•˜์—ฌ ์ •์ œ๋œ ๋ฐ์ดํ„ฐ์…‹์„ ์ƒ์„ฑํ•˜๊ณ , OpenAI GPT ๋ชจ๋ธ์„ ํ™œ์šฉํ•ด OCR ๊ฒฐ๊ณผ๋ฅผ ํ‰๊ฐ€ํ•œ ํ›„, ์ตœ์ข…์ ์œผ๋กœ ์ •๋ฆฌ๋œ ์˜์–‘ ์„ฑ๋ถ„ ๋ฐ ์›์žฌ๋ฃŒ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹์„ ์ƒ์„ฑํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ + - ์‹คํ–‰ ๋‹จ๊ณ„๋Š” OCR ๋ณ‘ํ•ฉ โ†’ ํ•™์Šต ๋ฐ์ดํ„ฐ ํ›„์ฒ˜๋ฆฌ โ†’ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ โ†’ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ ํ›„์ฒ˜๋ฆฌ ์ˆœ์„œ๋กœ ์ง„ํ–‰ \ No newline at end of file diff --git a/models/nutrition_ingredients_information/config/config.yaml b/models/nutrition_ingredients_information/config/config.yaml new file mode 100644 index 0000000..3f8990b --- /dev/null +++ b/models/nutrition_ingredients_information/config/config.yaml @@ -0,0 +1,8 @@ +# YOLO Training Configuration File + +train: /data/ephemeral/home/models/nutrition_ingredients_information/data/YOLO/train +val: +test: /data/ephemeral/home/models/nutrition_ingredients_information/data/YOLO/inference + +nc: 2 +names: ['nutrition','ingredient'] diff --git a/models/nutrition_ingredients_information/data/HCX/.gitkeep b/models/nutrition_ingredients_information/data/HCX/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/HCX/eval/.gitkeep b/models/nutrition_ingredients_information/data/HCX/eval/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/HCX/inference/.gitkeep b/models/nutrition_ingredients_information/data/HCX/inference/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/HCX/train/.gitkeep b/models/nutrition_ingredients_information/data/HCX/train/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/OCR/.gitkeep b/models/nutrition_ingredients_information/data/OCR/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/OCR/inference/.gitkeep b/models/nutrition_ingredients_information/data/OCR/inference/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/Rule-based/.gitkeep b/models/nutrition_ingredients_information/data/Rule-based/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/Rule-based/eval/.gitkeep b/models/nutrition_ingredients_information/data/Rule-based/eval/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/Rule-based/inference/.gitkeep b/models/nutrition_ingredients_information/data/Rule-based/inference/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/inference/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/inference/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/inference/images/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/inference/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/output/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/images/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/output/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1003.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1003.txt new file mode 100644 index 0000000..706e060 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1003.txt @@ -0,0 +1,2 @@ +0 0.5017431974411011 0.8010077476501465 0.4241745173931122 0.1859750896692276 +1 0.4995318353176117 0.40586304664611816 0.4252380132675171 0.6043249368667603 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1014.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1014.txt new file mode 100644 index 0000000..147322c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1014.txt @@ -0,0 +1,2 @@ +0 0.7420476078987122 0.7602734565734863 0.49174436926841736 0.23691335320472717 +1 0.4857659637928009 0.44764038920402527 0.9715319275856018 0.8944629430770874 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1023.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1023.txt new file mode 100644 index 0000000..9e716fb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1023.txt @@ -0,0 +1,2 @@ +1 0.3169628977775574 0.5007616877555847 0.3990916311740875 0.7921194434165955 +0 0.7045828104019165 0.7893663048744202 0.3556293547153473 0.20305024087429047 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1036.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1036.txt new file mode 100644 index 0000000..756583b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1036.txt @@ -0,0 +1,2 @@ +1 0.49805375933647156 0.30234435200691223 0.9901880025863647 0.6004850268363953 +0 0.21579276025295258 0.7896944880485535 0.43158552050590515 0.395912766456604 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart104.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart104.txt new file mode 100644 index 0000000..8cdf425 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart104.txt @@ -0,0 +1 @@ +1 0.4852658808231354 0.5093611478805542 0.6915624141693115 0.4795820415019989 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1044.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1044.txt new file mode 100644 index 0000000..5742fed --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1044.txt @@ -0,0 +1,2 @@ +1 0.49893301725387573 0.40976718068122864 0.7546537518501282 0.41649389266967773 +0 0.3911955654621124 0.7053878903388977 0.534619152545929 0.18405865132808685 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1054.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1054.txt new file mode 100644 index 0000000..9fafc61 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1054.txt @@ -0,0 +1,2 @@ +1 0.5 0.4493006765842438 1.0 0.8982110619544983 +0 0.7742589116096497 0.7296658158302307 0.4514821469783783 0.25278228521347046 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1064.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1064.txt new file mode 100644 index 0000000..caf6b53 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1064.txt @@ -0,0 +1 @@ +1 0.4964529871940613 0.5066993236541748 0.9895055890083313 0.9866014122962952 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1073.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1073.txt new file mode 100644 index 0000000..94623e6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1073.txt @@ -0,0 +1,2 @@ +0 0.8252951502799988 0.1985500603914261 0.17420852184295654 0.26398584246635437 +1 0.46659189462661743 0.6270256042480469 0.7938835620880127 0.6126489639282227 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1085.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1085.txt new file mode 100644 index 0000000..ce1073f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1085.txt @@ -0,0 +1,2 @@ +0 0.5008755922317505 0.16588546335697174 0.3502666652202606 0.24496984481811523 +1 0.5034632086753845 0.6375835537910461 0.4822688102722168 0.6236689686775208 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1096.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1096.txt new file mode 100644 index 0000000..cb5b9c1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1096.txt @@ -0,0 +1,2 @@ +1 0.5002074241638184 0.3524631857872009 0.6235748529434204 0.6429751515388489 +0 0.4998297393321991 0.8189746737480164 0.46541211009025574 0.28524962067604065 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1104.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1104.txt new file mode 100644 index 0000000..6a3f45d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1104.txt @@ -0,0 +1,2 @@ +1 0.507378876209259 0.40795108675956726 0.7287006974220276 0.45724064111709595 +0 0.41502413153648376 0.7258490920066833 0.5033001899719238 0.18391717970371246 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1114.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1114.txt new file mode 100644 index 0000000..3fa2fc7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1114.txt @@ -0,0 +1,2 @@ +0 0.48196789622306824 0.36175692081451416 0.7171445488929749 0.2471548169851303 +1 0.49723246693611145 0.6435219049453735 0.8658856153488159 0.18310217559337616 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1134.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1134.txt new file mode 100644 index 0000000..3c9426b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1134.txt @@ -0,0 +1,2 @@ +0 0.7147747278213501 0.5966123938560486 0.44912683963775635 0.1609259396791458 +1 0.2778007388114929 0.5055981874465942 0.44461703300476074 0.593863844871521 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart114.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart114.txt new file mode 100644 index 0000000..39cda96 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart114.txt @@ -0,0 +1,2 @@ +1 0.4985232949256897 0.42720910906791687 0.7777945399284363 0.3753443658351898 +0 0.49968987703323364 0.6794899106025696 0.7773287892341614 0.14502443373203278 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1144.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1144.txt new file mode 100644 index 0000000..790fe92 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1144.txt @@ -0,0 +1,2 @@ +0 0.7920907735824585 0.48750773072242737 0.3035646677017212 0.47254347801208496 +1 0.35915905237197876 0.5248321890830994 0.5614757537841797 0.5459967851638794 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1156.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1156.txt new file mode 100644 index 0000000..403215e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1156.txt @@ -0,0 +1,2 @@ +0 0.5 0.8722873330116272 1.0 0.25377047061920166 +1 0.5 0.37452012300491333 1.0 0.7439180016517639 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1163.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1163.txt new file mode 100644 index 0000000..707736d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1163.txt @@ -0,0 +1,2 @@ +0 0.6674803495407104 0.6551654934883118 0.26929327845573425 0.34418871998786926 +1 0.3949705958366394 0.49835866689682007 0.27246639132499695 0.6525946259498596 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1174.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1174.txt new file mode 100644 index 0000000..deeee47 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1174.txt @@ -0,0 +1,2 @@ +1 0.3208659589290619 0.4550090432167053 0.32903093099594116 0.6923947930335999 +0 0.6773191094398499 0.49899575114250183 0.3616821765899658 0.34261760115623474 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1184.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1184.txt new file mode 100644 index 0000000..a2dc0de --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1184.txt @@ -0,0 +1,3 @@ +1 0.36013004183769226 0.4997408986091614 0.5481665134429932 0.8446394205093384 +0 0.769946813583374 0.6041525602340698 0.2615913450717926 0.3200070858001709 +1 0.7723888754844666 0.2603414058685303 0.2603050470352173 0.3762625455856323 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1194.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1194.txt new file mode 100644 index 0000000..e9e0c79 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1194.txt @@ -0,0 +1,2 @@ +1 0.5008398294448853 0.49971213936805725 0.7044541835784912 0.26845666766166687 +0 0.6749922633171082 0.5675209164619446 0.358631432056427 0.1310504972934723 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1204.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1204.txt new file mode 100644 index 0000000..395c92f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1204.txt @@ -0,0 +1,2 @@ +1 0.5032616853713989 0.5131223797798157 0.7827315330505371 0.37095868587493896 +0 0.6883780360221863 0.5720113515853882 0.4259367287158966 0.2451101392507553 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1214.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1214.txt new file mode 100644 index 0000000..20cab3a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1214.txt @@ -0,0 +1,2 @@ +0 0.32556089758872986 0.5770198106765747 0.4159870445728302 0.49706870317459106 +1 0.7126911282539368 0.49005764722824097 0.318289577960968 0.7064547538757324 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1224.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1224.txt new file mode 100644 index 0000000..0afc9ba --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1224.txt @@ -0,0 +1,2 @@ +0 0.4903688430786133 0.7751047611236572 0.6147035956382751 0.20909437537193298 +1 0.49635687470436096 0.39351388812065125 0.6139113306999207 0.5619205832481384 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart123.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart123.txt new file mode 100644 index 0000000..badf9c8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart123.txt @@ -0,0 +1 @@ +1 0.50323086977005 0.4986400008201599 0.743381917476654 0.5232571363449097 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1234.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1234.txt new file mode 100644 index 0000000..47291b5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1234.txt @@ -0,0 +1,2 @@ +1 0.49985945224761963 0.4032604396343231 0.5593521595001221 0.5547573566436768 +0 0.5010198950767517 0.7802989482879639 0.562308669090271 0.20912107825279236 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1243.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1243.txt new file mode 100644 index 0000000..801f075 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1243.txt @@ -0,0 +1,2 @@ +0 0.6430246233940125 0.4064405560493469 0.2781601548194885 0.31307467818260193 +1 0.48615333437919617 0.492339551448822 0.5966736674308777 0.5126583576202393 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1253.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1253.txt new file mode 100644 index 0000000..a5bc114 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1253.txt @@ -0,0 +1,2 @@ +0 0.6890032887458801 0.6524809002876282 0.37038660049438477 0.32770252227783203 +1 0.3269229233264923 0.5149583220481873 0.31031838059425354 0.6152223944664001 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1266.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1266.txt new file mode 100644 index 0000000..ebeb103 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1266.txt @@ -0,0 +1,2 @@ +0 0.5059780478477478 0.7294542789459229 0.35414260625839233 0.48757123947143555 +1 0.5003282427787781 0.26443809270858765 0.7981952428817749 0.4073788523674011 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1274.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1274.txt new file mode 100644 index 0000000..321ce7d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1274.txt @@ -0,0 +1 @@ +1 0.48589009046554565 0.5056381821632385 0.44888511300086975 0.40796759724617004 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1296.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1296.txt new file mode 100644 index 0000000..a9dcac6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1296.txt @@ -0,0 +1,2 @@ +1 0.5072762966156006 0.4062577188014984 0.6417708992958069 0.6382163166999817 +0 0.5037806630134583 0.8191335201263428 0.6378902792930603 0.19615478813648224 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1307.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1307.txt new file mode 100644 index 0000000..3a5533d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1307.txt @@ -0,0 +1,2 @@ +1 0.5021098256111145 0.387788325548172 0.7150775194168091 0.6238665580749512 +0 0.5006744265556335 0.8102188110351562 0.7118848562240601 0.2301417589187622 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1313.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1313.txt new file mode 100644 index 0000000..12c00cd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1313.txt @@ -0,0 +1,2 @@ +1 0.5005871653556824 0.5198935866355896 0.7088181972503662 0.20747141540050507 +0 0.6524592638015747 0.5655170679092407 0.4221174418926239 0.10917778313159943 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1325.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1325.txt new file mode 100644 index 0000000..e2221e8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1325.txt @@ -0,0 +1,2 @@ +1 0.5007398724555969 0.3705151677131653 0.8908024430274963 0.28068047761917114 +0 0.4998050928115845 0.6768835186958313 0.803012490272522 0.2559121549129486 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1337.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1337.txt new file mode 100644 index 0000000..ad57094 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1337.txt @@ -0,0 +1,2 @@ +1 0.5035631060600281 0.6757843494415283 0.739386796951294 0.49741607904434204 +0 0.4959666430950165 0.22619251906871796 0.4938640594482422 0.30341532826423645 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1344.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1344.txt new file mode 100644 index 0000000..77356f1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1344.txt @@ -0,0 +1,2 @@ +0 0.7477272152900696 0.5466001033782959 0.42669564485549927 0.32370415329933167 +1 0.2403951734304428 0.4786849021911621 0.4203069508075714 0.42201724648475647 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1355.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1355.txt new file mode 100644 index 0000000..2491d4e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1355.txt @@ -0,0 +1,2 @@ +0 0.6272633671760559 0.5314797163009644 0.28962624073028564 0.38570213317871094 +1 0.3486635982990265 0.4164642095565796 0.24765878915786743 0.6333766579627991 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1366.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1366.txt new file mode 100644 index 0000000..a86095e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1366.txt @@ -0,0 +1,2 @@ +0 0.8332752585411072 0.421867311000824 0.24831588566303253 0.27555906772613525 +1 0.3698747158050537 0.4971454441547394 0.6728183031082153 0.4417799115180969 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1375.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1375.txt new file mode 100644 index 0000000..c556f52 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1375.txt @@ -0,0 +1 @@ +1 0.501010000705719 0.5279108285903931 0.9134319424629211 0.9320148825645447 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1395.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1395.txt new file mode 100644 index 0000000..733a677 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1395.txt @@ -0,0 +1,2 @@ +0 0.7084029912948608 0.5511023998260498 0.4363496005535126 0.3043871521949768 +1 0.49478214979171753 0.4992697834968567 0.8677159547805786 0.40640851855278015 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1404.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1404.txt new file mode 100644 index 0000000..1132d07 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1404.txt @@ -0,0 +1,2 @@ +1 0.4986140727996826 0.614299476146698 0.5743315815925598 0.3321422338485718 +0 0.6537179946899414 0.6683507561683655 0.26228564977645874 0.15896931290626526 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1417.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1417.txt new file mode 100644 index 0000000..20ea87b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1417.txt @@ -0,0 +1 @@ +1 0.5017244219779968 0.5186978578567505 0.8083905577659607 0.2339356243610382 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1424.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1424.txt new file mode 100644 index 0000000..f4ce776 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1424.txt @@ -0,0 +1,2 @@ +1 0.34837713837623596 0.49068936705589294 0.33234134316444397 0.47725147008895874 +0 0.6815569996833801 0.5763734579086304 0.322040855884552 0.3114294111728668 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart143.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart143.txt new file mode 100644 index 0000000..abb6762 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart143.txt @@ -0,0 +1 @@ +1 0.49759265780448914 0.4986570477485657 0.5728024244308472 0.36386018991470337 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1433.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1433.txt new file mode 100644 index 0000000..38afa93 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1433.txt @@ -0,0 +1,2 @@ +1 0.49985432624816895 0.2890516519546509 0.5025678873062134 0.3076692819595337 +0 0.4925418496131897 0.6680773496627808 0.2733982503414154 0.42037564516067505 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1443.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1443.txt new file mode 100644 index 0000000..2fcc108 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1443.txt @@ -0,0 +1,2 @@ +1 0.3687906563282013 0.49920839071273804 0.5268911719322205 0.563377320766449 +0 0.7572517991065979 0.38606688380241394 0.26457032561302185 0.3433087170124054 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1457.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1457.txt new file mode 100644 index 0000000..533f1fb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1457.txt @@ -0,0 +1 @@ +1 0.4941140115261078 0.4909276068210602 0.9882280230522156 0.9818552136421204 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1464.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1464.txt new file mode 100644 index 0000000..355c3bd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1464.txt @@ -0,0 +1,2 @@ +1 0.49546632170677185 0.3462361693382263 0.882792592048645 0.5764569640159607 +0 0.4320524334907532 0.7858780026435852 0.7561209797859192 0.3070026636123657 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1477.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1477.txt new file mode 100644 index 0000000..a77d687 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1477.txt @@ -0,0 +1,3 @@ +0 0.7067273855209351 0.7882429361343384 0.26420581340789795 0.1685800552368164 +1 0.7072900533676147 0.5143344402313232 0.26919519901275635 0.37889108061790466 +1 0.1865731030702591 0.05973432958126068 0.37264105677604675 0.11785944551229477 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1484.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1484.txt new file mode 100644 index 0000000..2971e70 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1484.txt @@ -0,0 +1 @@ +1 0.49841994047164917 0.516174852848053 0.6426196694374084 0.5786135792732239 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1493.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1493.txt new file mode 100644 index 0000000..49b00f5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1493.txt @@ -0,0 +1,2 @@ +0 0.7323977947235107 0.38325706124305725 0.31612664461135864 0.30077606439590454 +1 0.33283531665802 0.4977046549320221 0.45586898922920227 0.5246815085411072 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1506.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1506.txt new file mode 100644 index 0000000..30eca3d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1506.txt @@ -0,0 +1 @@ +1 0.4940313696861267 0.5069669485092163 0.5388352274894714 0.8076704144477844 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1514.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1514.txt new file mode 100644 index 0000000..37e8bdb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1514.txt @@ -0,0 +1 @@ +1 0.5033623576164246 0.4835737943649292 0.8058043718338013 0.18449771404266357 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1533.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1533.txt new file mode 100644 index 0000000..0109769 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1533.txt @@ -0,0 +1 @@ +1 0.49715399742126465 0.49892503023147583 0.784686803817749 0.37579345703125 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1544.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1544.txt new file mode 100644 index 0000000..8f8fc6a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1544.txt @@ -0,0 +1,3 @@ +0 0.7386881113052368 0.4774651825428009 0.3232995569705963 0.14553433656692505 +1 0.3369807004928589 0.43802693486213684 0.4809519946575165 0.572561502456665 +1 0.4999616742134094 0.4427662193775177 0.810911238193512 0.590588390827179 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1563.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1563.txt new file mode 100644 index 0000000..0fc4a9e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1563.txt @@ -0,0 +1 @@ +1 0.49957430362701416 0.498305082321167 0.805732011795044 0.1377774327993393 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1605.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1605.txt new file mode 100644 index 0000000..9baaa43 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1605.txt @@ -0,0 +1 @@ +1 0.5001176595687866 0.5 0.9962953925132751 1.0 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1616.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1616.txt new file mode 100644 index 0000000..2d8e05c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1616.txt @@ -0,0 +1 @@ +1 0.4949299395084381 0.5559510588645935 0.9755955338478088 0.8786319494247437 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1623.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1623.txt new file mode 100644 index 0000000..af8d16e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1623.txt @@ -0,0 +1 @@ +1 0.5134917497634888 0.39120832085609436 0.9375922679901123 0.7701585292816162 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1633.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1633.txt new file mode 100644 index 0000000..fa647f8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1633.txt @@ -0,0 +1,2 @@ +1 0.498050719499588 0.3694993555545807 0.6514616012573242 0.48585614562034607 +0 0.44670993089675903 0.7420924305915833 0.537865936756134 0.25723326206207275 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1645.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1645.txt new file mode 100644 index 0000000..2e1173a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1645.txt @@ -0,0 +1 @@ +1 0.5231736898422241 0.46706801652908325 0.5582903623580933 0.3230634927749634 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1656.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1656.txt new file mode 100644 index 0000000..cd4a9da --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1656.txt @@ -0,0 +1,2 @@ +0 0.7704054713249207 0.36795175075531006 0.455371230840683 0.7073380947113037 +1 0.2710903286933899 0.4628312885761261 0.5402737259864807 0.8959864377975464 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart166.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart166.txt new file mode 100644 index 0000000..7f10202 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart166.txt @@ -0,0 +1 @@ +1 0.4999949336051941 0.4984591007232666 0.9947385191917419 0.9944487810134888 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1674.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1674.txt new file mode 100644 index 0000000..3d6ab13 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1674.txt @@ -0,0 +1,2 @@ +0 0.28977546095848083 0.5104579329490662 0.31729987263679504 0.49953508377075195 +1 0.6654272675514221 0.5014429092407227 0.4069172143936157 0.5181097984313965 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1695.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1695.txt new file mode 100644 index 0000000..6b38f1d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1695.txt @@ -0,0 +1,2 @@ +0 0.701205313205719 0.6099533438682556 0.3736245930194855 0.39479485154151917 +1 0.308549702167511 0.6701544523239136 0.40924304723739624 0.43714696168899536 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1705.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1705.txt new file mode 100644 index 0000000..a8347e2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1705.txt @@ -0,0 +1 @@ +1 0.5 0.4985814690589905 1.0 0.997162938117981 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1713.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1713.txt new file mode 100644 index 0000000..ba7299e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1713.txt @@ -0,0 +1,2 @@ +1 0.277103066444397 0.4980528950691223 0.3148607313632965 0.5888208746910095 +0 0.6581551432609558 0.497837096452713 0.4445529878139496 0.26746928691864014 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1724.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1724.txt new file mode 100644 index 0000000..30633a0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1724.txt @@ -0,0 +1 @@ +1 0.5009632706642151 0.5202168226242065 0.5865880250930786 0.403816819190979 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1733.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1733.txt new file mode 100644 index 0000000..e0b76c3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1733.txt @@ -0,0 +1,2 @@ +0 0.47047188878059387 0.8103617429733276 0.2114984691143036 0.24138718843460083 +1 0.4968329071998596 0.3735557794570923 0.2594345808029175 0.639151930809021 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart174.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart174.txt new file mode 100644 index 0000000..aa45740 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart174.txt @@ -0,0 +1 @@ +1 0.4960753917694092 0.518355131149292 0.6351312398910522 0.5124948024749756 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1764.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1764.txt new file mode 100644 index 0000000..3d762a0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1764.txt @@ -0,0 +1 @@ +1 0.5008642077445984 0.44520047307014465 0.9114558100700378 0.8517026305198669 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1774.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1774.txt new file mode 100644 index 0000000..bb11aef --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1774.txt @@ -0,0 +1,2 @@ +1 0.654768168926239 0.49696800112724304 0.587204098701477 0.21819466352462769 +0 0.21284964680671692 0.4661305248737335 0.3021696209907532 0.15323799848556519 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1784.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1784.txt new file mode 100644 index 0000000..f51c8ea --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1784.txt @@ -0,0 +1,2 @@ +0 0.4994787573814392 0.6388755440711975 0.26015377044677734 0.6135274767875671 +1 0.5171629786491394 0.18121632933616638 0.6956568360328674 0.26214322447776794 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1804.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1804.txt new file mode 100644 index 0000000..c816690 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1804.txt @@ -0,0 +1 @@ +1 0.5134214758872986 0.5136830806732178 0.6147317290306091 0.4358825981616974 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1816.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1816.txt new file mode 100644 index 0000000..94a3634 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1816.txt @@ -0,0 +1 @@ +1 0.49499645829200745 0.5245076417922974 0.9112052917480469 0.8331612944602966 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1833.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1833.txt new file mode 100644 index 0000000..555cab9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1833.txt @@ -0,0 +1,2 @@ +0 0.4969189465045929 0.7691493630409241 0.7718390822410583 0.21160927414894104 +1 0.4957868754863739 0.3921663761138916 0.7730465531349182 0.5360782146453857 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1856.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1856.txt new file mode 100644 index 0000000..d42ebb3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1856.txt @@ -0,0 +1 @@ +1 0.5004603266716003 0.5021749138832092 0.9941466450691223 0.9787585735321045 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1893.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1893.txt new file mode 100644 index 0000000..394db6f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1893.txt @@ -0,0 +1 @@ +1 0.498735636472702 0.4466935694217682 0.5656067132949829 0.6699326038360596 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1905.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1905.txt new file mode 100644 index 0000000..4f57275 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1905.txt @@ -0,0 +1 @@ +0 0.4991261065006256 0.49581581354141235 0.9865795373916626 0.9552249312400818 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1913.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1913.txt new file mode 100644 index 0000000..176cc1e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1913.txt @@ -0,0 +1 @@ +1 0.49966567754745483 0.4978829622268677 0.7988964319229126 0.4002310037612915 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1924.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1924.txt new file mode 100644 index 0000000..e70ee4e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1924.txt @@ -0,0 +1 @@ +1 0.5003426671028137 0.5017204284667969 0.9899348020553589 0.9723023772239685 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1965.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1965.txt new file mode 100644 index 0000000..77135b4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1965.txt @@ -0,0 +1 @@ +1 0.49158018827438354 0.5236552953720093 0.9262503981590271 0.6948471665382385 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1973.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1973.txt new file mode 100644 index 0000000..2a1c4b8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1973.txt @@ -0,0 +1,4 @@ +0 0.8129958510398865 0.6965355277061462 0.3400012254714966 0.5779674649238586 +1 0.5 0.4993632435798645 1.0 0.998726487159729 +1 0.3242008090019226 0.6454273462295532 0.6484016180038452 0.6879561543464661 +1 0.5 0.3234252333641052 1.0 0.6441605687141418 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1996.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1996.txt new file mode 100644 index 0000000..86876ea --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart1996.txt @@ -0,0 +1 @@ +1 0.4993935823440552 0.4951171576976776 0.9982584118843079 0.9704296588897705 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2004.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2004.txt new file mode 100644 index 0000000..e1d1366 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2004.txt @@ -0,0 +1,2 @@ +1 0.533710777759552 0.35363516211509705 0.4075759947299957 0.47027915716171265 +0 0.4420200288295746 0.7540924549102783 0.21998921036720276 0.2880256175994873 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2016.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2016.txt new file mode 100644 index 0000000..b4297ab --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2016.txt @@ -0,0 +1 @@ +1 0.499085396528244 0.4981859028339386 0.9944791793823242 0.9743108153343201 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2035.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2035.txt new file mode 100644 index 0000000..e964788 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2035.txt @@ -0,0 +1 @@ +1 0.5070641040802002 0.4825291335582733 0.9686840176582336 0.7021468281745911 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2056.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2056.txt new file mode 100644 index 0000000..3b6cf14 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2056.txt @@ -0,0 +1 @@ +1 0.5025507211685181 0.4941076636314392 0.8954654932022095 0.6365009546279907 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2065.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2065.txt new file mode 100644 index 0000000..8570387 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2065.txt @@ -0,0 +1,2 @@ +1 0.4987477660179138 0.23469820618629456 0.7018182873725891 0.25158050656318665 +0 0.5013388991355896 0.624060332775116 0.6686078906059265 0.5152844786643982 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2106.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2106.txt new file mode 100644 index 0000000..791a53e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2106.txt @@ -0,0 +1 @@ +1 0.4925192892551422 0.5002344250679016 0.9015538692474365 0.45739755034446716 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2116.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2116.txt new file mode 100644 index 0000000..9f29ee6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2116.txt @@ -0,0 +1 @@ +1 0.496955931186676 0.38955894112586975 0.9849808216094971 0.695490300655365 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2126.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2126.txt new file mode 100644 index 0000000..37bdd1b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2126.txt @@ -0,0 +1 @@ +1 0.46855461597442627 0.4872911870479584 0.8824461102485657 0.37017515301704407 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart213.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart213.txt new file mode 100644 index 0000000..a6e8665 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart213.txt @@ -0,0 +1 @@ +1 0.5103518962860107 0.498949259519577 0.8556619882583618 0.09814707934856415 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2134.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2134.txt new file mode 100644 index 0000000..f9b21dc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2134.txt @@ -0,0 +1 @@ +1 0.5053082704544067 0.49599689245224 0.5956881642341614 0.38633447885513306 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2143.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2143.txt new file mode 100644 index 0000000..dab4df2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2143.txt @@ -0,0 +1 @@ +1 0.4950515329837799 0.4989059269428253 0.8072381615638733 0.34605923295021057 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2164.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2164.txt new file mode 100644 index 0000000..a7b049b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2164.txt @@ -0,0 +1,2 @@ +1 0.43240830302238464 0.4690393805503845 0.5861219167709351 0.48001229763031006 +0 0.7972599267959595 0.49810275435447693 0.1388702392578125 0.537831723690033 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2184.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2184.txt new file mode 100644 index 0000000..0255fec --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2184.txt @@ -0,0 +1 @@ +1 0.5020017623901367 0.49972930550575256 0.7119371891021729 0.32516491413116455 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2196.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2196.txt new file mode 100644 index 0000000..ca5d030 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2196.txt @@ -0,0 +1 @@ +1 0.5006203055381775 0.37365615367889404 0.968732476234436 0.7473123073577881 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2224.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2224.txt new file mode 100644 index 0000000..a4fbcfe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2224.txt @@ -0,0 +1 @@ +1 0.4965853989124298 0.500206708908081 0.9367991089820862 0.24651262164115906 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2236.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2236.txt new file mode 100644 index 0000000..ab81cc1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2236.txt @@ -0,0 +1 @@ +1 0.4988955855369568 0.5028353929519653 0.9949961304664612 0.9797968864440918 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2246.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2246.txt new file mode 100644 index 0000000..4fb8c6d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2246.txt @@ -0,0 +1 @@ +1 0.4935920834541321 0.5026164650917053 0.9479354619979858 0.5410751104354858 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2254.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2254.txt new file mode 100644 index 0000000..0bc2672 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2254.txt @@ -0,0 +1,2 @@ +1 0.37471750378608704 0.5273665189743042 0.5000928044319153 0.27113959193229675 +0 0.7489867210388184 0.5212345123291016 0.25003841519355774 0.24739685654640198 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2274.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2274.txt new file mode 100644 index 0000000..d961693 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2274.txt @@ -0,0 +1 @@ +1 0.49503862857818604 0.4838983714580536 0.6200451254844666 0.25163954496383667 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2286.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2286.txt new file mode 100644 index 0000000..75ad508 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2286.txt @@ -0,0 +1 @@ +1 0.5061150193214417 0.49984845519065857 0.95391446352005 0.3924804925918579 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2294.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2294.txt new file mode 100644 index 0000000..1b9e914 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2294.txt @@ -0,0 +1 @@ +1 0.4969506859779358 0.5134456157684326 0.6050394773483276 0.2710982859134674 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2314.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2314.txt new file mode 100644 index 0000000..2e6a0a6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2314.txt @@ -0,0 +1,2 @@ +1 0.503514289855957 0.40719902515411377 0.7461650967597961 0.4570271372795105 +0 0.49983274936676025 0.7315014004707336 0.7517162561416626 0.17650605738162994 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart233.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart233.txt new file mode 100644 index 0000000..cf471e8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart233.txt @@ -0,0 +1 @@ +1 0.4924657344818115 0.506203293800354 0.6137875914573669 0.4139631986618042 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2334.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2334.txt new file mode 100644 index 0000000..4416309 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2334.txt @@ -0,0 +1,2 @@ +0 0.4976600408554077 0.7421112060546875 0.790488064289093 0.5067479610443115 +1 0.4987374246120453 0.24795395135879517 0.9938338398933411 0.49297136068344116 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2344.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2344.txt new file mode 100644 index 0000000..4eb8f5c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2344.txt @@ -0,0 +1,2 @@ +0 0.3486572504043579 0.6585767865180969 0.45017334818840027 0.18198472261428833 +1 0.49990275502204895 0.4118860960006714 0.749848484992981 0.3177870213985443 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2364.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2364.txt new file mode 100644 index 0000000..e937af3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2364.txt @@ -0,0 +1 @@ +1 0.4979531764984131 0.5178881883621216 0.7842576503753662 0.46375906467437744 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2396.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2396.txt new file mode 100644 index 0000000..31c7200 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2396.txt @@ -0,0 +1 @@ +1 0.4992162883281708 0.5030534267425537 0.9984325766563416 0.9938932657241821 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart24.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart24.txt new file mode 100644 index 0000000..64f97e5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart24.txt @@ -0,0 +1 @@ +1 0.4738946259021759 0.4974137842655182 0.6565252542495728 0.5113601684570312 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2414.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2414.txt new file mode 100644 index 0000000..8e8f36f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2414.txt @@ -0,0 +1,2 @@ +1 0.4989140033721924 0.41782504320144653 0.6944582462310791 0.5046795606613159 +0 0.38916245102882385 0.7540077567100525 0.47795096039772034 0.17107360064983368 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2423.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2423.txt new file mode 100644 index 0000000..b5505d8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2423.txt @@ -0,0 +1,2 @@ +1 0.5006743669509888 0.5049052238464355 0.903304934501648 0.9722070693969727 +0 0.7406799793243408 0.7289305329322815 0.3948909342288971 0.5061557292938232 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2434.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2434.txt new file mode 100644 index 0000000..80de1b5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2434.txt @@ -0,0 +1,2 @@ +0 0.39770594239234924 0.7944149374961853 0.27011534571647644 0.06319529563188553 +1 0.49218490719795227 0.680383563041687 0.47811728715896606 0.1663665920495987 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart244.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart244.txt new file mode 100644 index 0000000..ae10921 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart244.txt @@ -0,0 +1 @@ +1 0.49981239438056946 0.5054491758346558 0.6015612483024597 0.43165743350982666 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2443.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2443.txt new file mode 100644 index 0000000..5c4fb9b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2443.txt @@ -0,0 +1,2 @@ +0 0.658198356628418 0.6204145550727844 0.48153403401374817 0.16710294783115387 +1 0.4992634057998657 0.47872060537338257 0.7989639639854431 0.4525914192199707 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2453.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2453.txt new file mode 100644 index 0000000..0a3e015 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2453.txt @@ -0,0 +1,2 @@ +0 0.6832857131958008 0.7225862741470337 0.37060797214508057 0.2244621366262436 +1 0.3013720214366913 0.5007529854774475 0.336192786693573 0.6733390092849731 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2463.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2463.txt new file mode 100644 index 0000000..1d467f4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2463.txt @@ -0,0 +1,2 @@ +0 0.49431493878364563 0.5982416272163391 0.7369085550308228 0.1329113095998764 +1 0.4926456809043884 0.4456542432308197 0.7257037162780762 0.1209518164396286 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2474.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2474.txt new file mode 100644 index 0000000..0d5bae6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2474.txt @@ -0,0 +1,2 @@ +0 0.5105094909667969 0.4253917634487152 0.9351257085800171 0.2840845584869385 +1 0.5074433088302612 0.6743277311325073 0.9601576328277588 0.1521727293729782 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2493.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2493.txt new file mode 100644 index 0000000..ce16b62 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2493.txt @@ -0,0 +1,2 @@ +1 0.4998808801174164 0.5004812479019165 0.772925078868866 0.1597963124513626 +0 0.7052267789840698 0.4551135301589966 0.38275253772735596 0.07212524861097336 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2504.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2504.txt new file mode 100644 index 0000000..a1354ab --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2504.txt @@ -0,0 +1,2 @@ +1 0.4859335720539093 0.6338821649551392 0.5984090566635132 0.21060754358768463 +0 0.3639224171638489 0.7827229499816895 0.3554842174053192 0.08333168178796768 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2513.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2513.txt new file mode 100644 index 0000000..059363d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2513.txt @@ -0,0 +1,2 @@ +0 0.7232146263122559 0.6660423874855042 0.3478189706802368 0.45375484228134155 +1 0.31022870540618896 0.49999940395355225 0.40983372926712036 0.7899125814437866 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2524.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2524.txt new file mode 100644 index 0000000..0c01e9f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2524.txt @@ -0,0 +1,2 @@ +1 0.5026952028274536 0.4265199303627014 0.7557089328765869 0.27679720520973206 +0 0.5003744959831238 0.6443228721618652 0.7458412647247314 0.13156528770923615 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart253.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart253.txt new file mode 100644 index 0000000..e60e1fe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart253.txt @@ -0,0 +1 @@ +1 0.5106569528579712 0.49328377842903137 0.565505862236023 0.6684198975563049 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2533.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2533.txt new file mode 100644 index 0000000..8f8444d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2533.txt @@ -0,0 +1,2 @@ +1 0.31195399165153503 0.49198877811431885 0.342740535736084 0.4737548828125 +0 0.6803485155105591 0.5998518466949463 0.38972723484039307 0.2477005124092102 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2553.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2553.txt new file mode 100644 index 0000000..b5500ad --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2553.txt @@ -0,0 +1,6 @@ +1 0.49905046820640564 0.5242050886154175 0.9981009364128113 0.7454006671905518 +0 0.4987576901912689 0.3923830986022949 0.9952746629714966 0.16392536461353302 +1 0.4986266493797302 0.2835656702518463 0.9972532987594604 0.38755035400390625 +0 0.7965121865272522 0.392801433801651 0.4052238464355469 0.1506836861371994 +0 0.5007890462875366 0.32140037417411804 0.998421847820282 0.3219899535179138 +0 0.21114209294319153 0.39797109365463257 0.41859492659568787 0.16339373588562012 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2564.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2564.txt new file mode 100644 index 0000000..961320e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2564.txt @@ -0,0 +1,2 @@ +1 0.4988531470298767 0.4520413875579834 0.47562792897224426 0.6543981432914734 +0 0.49805107712745667 0.8402271866798401 0.4713359475135803 0.12519118189811707 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2573.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2573.txt new file mode 100644 index 0000000..e70f509 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2573.txt @@ -0,0 +1,2 @@ +0 0.5010472536087036 0.8103829026222229 0.3865644633769989 0.17811839282512665 +1 0.49661123752593994 0.41505977511405945 0.3515121340751648 0.6095983982086182 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2584.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2584.txt new file mode 100644 index 0000000..c1c9886 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2584.txt @@ -0,0 +1,2 @@ +1 0.5028843283653259 0.40853407979011536 0.6049281358718872 0.5426086783409119 +0 0.5031158924102783 0.7662416100502014 0.5870243906974792 0.1751401424407959 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2594.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2594.txt new file mode 100644 index 0000000..ef066a2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2594.txt @@ -0,0 +1,2 @@ +0 0.6989206075668335 0.6187268495559692 0.4043917655944824 0.4382651448249817 +1 0.28439751267433167 0.49698585271835327 0.36562883853912354 0.6781849265098572 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2604.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2604.txt new file mode 100644 index 0000000..0afe6fe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2604.txt @@ -0,0 +1,2 @@ +0 0.48508280515670776 0.427688866853714 0.8149572610855103 0.25176724791526794 +1 0.480583518743515 0.6550275087356567 0.8399999141693115 0.13592952489852905 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2614.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2614.txt new file mode 100644 index 0000000..a15011e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2614.txt @@ -0,0 +1,3 @@ +1 0.5008586645126343 0.5052611827850342 0.90072101354599 0.9691916704177856 +0 0.7369652390480042 0.27647629380226135 0.41601425409317017 0.5200361609458923 +0 0.7376068830490112 0.5058002471923828 0.41487711668014526 0.9761725664138794 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2624.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2624.txt new file mode 100644 index 0000000..3c9426b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2624.txt @@ -0,0 +1,2 @@ +0 0.7147747278213501 0.5966123938560486 0.44912683963775635 0.1609259396791458 +1 0.2778007388114929 0.5055981874465942 0.44461703300476074 0.593863844871521 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2634.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2634.txt new file mode 100644 index 0000000..d233d6f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2634.txt @@ -0,0 +1,2 @@ +0 0.6721476316452026 0.633295476436615 0.34381383657455444 0.3423706293106079 +1 0.3197328448295593 0.502107560634613 0.32088688015937805 0.6213899254798889 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart264.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart264.txt new file mode 100644 index 0000000..da7093d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart264.txt @@ -0,0 +1,2 @@ +0 0.24226997792720795 0.6361916065216064 0.4302748441696167 0.13133291900157928 +1 0.5049092769622803 0.4364984929561615 0.9367567300796509 0.2674837112426758 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2646.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2646.txt new file mode 100644 index 0000000..2e263ed --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2646.txt @@ -0,0 +1,2 @@ +0 0.764032244682312 0.2544455826282501 0.4594518542289734 0.5088911652565002 +1 0.4989640712738037 0.5 0.9958914518356323 1.0 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2653.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2653.txt new file mode 100644 index 0000000..0a255e2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2653.txt @@ -0,0 +1,2 @@ +1 0.5021640658378601 0.41038164496421814 0.5496143102645874 0.5327256321907043 +0 0.5020779371261597 0.7633883357048035 0.5252298712730408 0.17601682245731354 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2663.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2663.txt new file mode 100644 index 0000000..f206a9c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2663.txt @@ -0,0 +1,2 @@ +1 0.4935597777366638 0.4977375864982605 0.9275213479995728 0.9875668883323669 +0 0.7574638724327087 0.7498750686645508 0.38598522543907166 0.491057425737381 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2673.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2673.txt new file mode 100644 index 0000000..98a57e3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2673.txt @@ -0,0 +1,2 @@ +1 0.49686115980148315 0.3497813642024994 0.6178897023200989 0.485732764005661 +0 0.49739566445350647 0.6973854303359985 0.6168695092201233 0.22129938006401062 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2684.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2684.txt new file mode 100644 index 0000000..c8fcb5b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2684.txt @@ -0,0 +1,2 @@ +0 0.8327594995498657 0.3907599449157715 0.33241623640060425 0.5507317185401917 +1 0.3349524736404419 0.49605461955070496 0.6699049472808838 0.7602396607398987 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2703.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2703.txt new file mode 100644 index 0000000..b3e1147 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2703.txt @@ -0,0 +1,2 @@ +0 0.4983612298965454 0.5685628652572632 0.7221519947052002 0.21251508593559265 +1 0.501701831817627 0.3880726099014282 0.7491270899772644 0.12659035623073578 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2714.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2714.txt new file mode 100644 index 0000000..fa41e71 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2714.txt @@ -0,0 +1,2 @@ +1 0.49871909618377686 0.2787974774837494 0.9974381923675537 0.4514061212539673 +0 0.49983084201812744 0.7372032999992371 0.4501209557056427 0.4286658465862274 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2723.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2723.txt new file mode 100644 index 0000000..1436e4b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2723.txt @@ -0,0 +1,2 @@ +1 0.49202704429626465 0.49551498889923096 0.7476037740707397 0.2130696028470993 +0 0.5826536417007446 0.45140746235847473 0.34071072936058044 0.10803617537021637 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart273.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart273.txt new file mode 100644 index 0000000..0515cc9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart273.txt @@ -0,0 +1 @@ +1 0.48367300629615784 0.4874073266983032 0.47269973158836365 0.5552765130996704 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2734.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2734.txt new file mode 100644 index 0000000..9eba615 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2734.txt @@ -0,0 +1,2 @@ +0 0.4870581030845642 0.7721489071846008 0.3650422990322113 0.18573494255542755 +1 0.4885989725589752 0.3857298195362091 0.37442895770072937 0.49191606044769287 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2743.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2743.txt new file mode 100644 index 0000000..53e38d6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2743.txt @@ -0,0 +1,2 @@ +0 0.5063397884368896 0.7612130641937256 0.4083532691001892 0.21313723921775818 +1 0.506702184677124 0.399831622838974 0.4135332703590393 0.5114902853965759 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2754.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2754.txt new file mode 100644 index 0000000..cfe4cda --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2754.txt @@ -0,0 +1,2 @@ +1 0.4945182204246521 0.49050372838974 0.733487606048584 0.4106999635696411 +0 0.4979014992713928 0.8081780076026917 0.6979690194129944 0.1341557800769806 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2774.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2774.txt new file mode 100644 index 0000000..f88cf46 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2774.txt @@ -0,0 +1,2 @@ +1 0.5005246996879578 0.3649415075778961 0.9187309741973877 0.6718420386314392 +0 0.5039801597595215 0.8356038928031921 0.9164392352104187 0.2631135582923889 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2784.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2784.txt new file mode 100644 index 0000000..d1a8ec4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2784.txt @@ -0,0 +1,3 @@ +0 0.26196300983428955 0.3937208354473114 0.4561382532119751 0.5580538511276245 +1 0.7198878526687622 0.5192172527313232 0.466155469417572 0.8107123374938965 +0 0.2597470283508301 0.7652246356010437 0.4513750970363617 0.18409191071987152 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2794.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2794.txt new file mode 100644 index 0000000..b5ab861 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2794.txt @@ -0,0 +1,2 @@ +0 0.4955073297023773 0.6823636889457703 0.7128264307975769 0.23128516972064972 +1 0.5008520483970642 0.38366591930389404 0.7370896935462952 0.309778094291687 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2806.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2806.txt new file mode 100644 index 0000000..5b746c4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2806.txt @@ -0,0 +1,2 @@ +0 0.6712732911109924 0.22752436995506287 0.4423513114452362 0.3055647015571594 +1 0.4974006414413452 0.6494358777999878 0.7676975727081299 0.5350223779678345 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2814.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2814.txt new file mode 100644 index 0000000..26de3d7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2814.txt @@ -0,0 +1,2 @@ +0 0.5227385759353638 0.1970938742160797 0.3394390046596527 0.32800689339637756 +1 0.5231819152832031 0.6141366958618164 0.33616387844085693 0.5094500184059143 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2824.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2824.txt new file mode 100644 index 0000000..1f1eb98 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2824.txt @@ -0,0 +1,2 @@ +1 0.4973732531070709 0.33768561482429504 0.9137793779373169 0.4357643127441406 +0 0.4967290461063385 0.8181007504463196 0.9099054932594299 0.2724010944366455 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2835.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2835.txt new file mode 100644 index 0000000..6316632 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2835.txt @@ -0,0 +1,2 @@ +0 0.35998427867889404 0.842096209526062 0.6665374040603638 0.2808702290058136 +1 0.4847053289413452 0.3585430383682251 0.9291355013847351 0.6786947846412659 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart284.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart284.txt new file mode 100644 index 0000000..e0d7c8b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart284.txt @@ -0,0 +1 @@ +1 0.4951193928718567 0.499450147151947 0.7311758399009705 0.6898308396339417 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2843.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2843.txt new file mode 100644 index 0000000..50fce3c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2843.txt @@ -0,0 +1,2 @@ +0 0.7830992937088013 0.7089680433273315 0.3404058516025543 0.47334015369415283 +1 0.49567580223083496 0.4900396466255188 0.9415270090103149 0.9270023703575134 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2854.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2854.txt new file mode 100644 index 0000000..a17b5ba --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2854.txt @@ -0,0 +1,2 @@ +1 0.6792263984680176 0.4976468086242676 0.5590516328811646 0.8836077451705933 +0 0.2598174810409546 0.4100210666656494 0.2652096152305603 0.7055349349975586 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2864.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2864.txt new file mode 100644 index 0000000..b0fbffc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2864.txt @@ -0,0 +1,2 @@ +0 0.7859876751899719 0.5016953349113464 0.4195564091205597 0.9586973786354065 +1 0.29373350739479065 0.49939385056495667 0.5619681477546692 0.9502516388893127 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2874.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2874.txt new file mode 100644 index 0000000..0ea95b9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2874.txt @@ -0,0 +1,2 @@ +0 0.4981616139411926 0.7895013689994812 0.7258961200714111 0.1363517940044403 +1 0.49542948603630066 0.49609342217445374 0.7349042892456055 0.40529996156692505 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2884.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2884.txt new file mode 100644 index 0000000..0e53195 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2884.txt @@ -0,0 +1,2 @@ +1 0.4988310933113098 0.29999881982803345 0.9946687817573547 0.5853195786476135 +0 0.4350840151309967 0.745743453502655 0.8610995411872864 0.30293580889701843 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2905.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2905.txt new file mode 100644 index 0000000..6786a0a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2905.txt @@ -0,0 +1,2 @@ +0 0.7285696268081665 0.711373507976532 0.48463308811187744 0.452458918094635 +1 0.5096646547317505 0.4992908835411072 0.9771829843521118 0.9127714037895203 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2914.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2914.txt new file mode 100644 index 0000000..155378c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2914.txt @@ -0,0 +1,2 @@ +0 0.751599907875061 0.5708215236663818 0.4238933026790619 0.2626931965351105 +1 0.282940149307251 0.5419344902038574 0.44355738162994385 0.5943527221679688 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2924.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2924.txt new file mode 100644 index 0000000..805287c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2924.txt @@ -0,0 +1,2 @@ +0 0.7541541457176208 0.5194268226623535 0.26645001769065857 0.34648802876472473 +1 0.3646300137042999 0.4969940185546875 0.5014647841453552 0.3883577585220337 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2933.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2933.txt new file mode 100644 index 0000000..eee20ec --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2933.txt @@ -0,0 +1,2 @@ +1 0.49439483880996704 0.49591416120529175 0.6486989855766296 0.6847439408302307 +0 0.652334988117218 0.27104291319847107 0.2890002727508545 0.2183903306722641 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart294.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart294.txt new file mode 100644 index 0000000..3dd8996 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart294.txt @@ -0,0 +1 @@ +1 0.5025264024734497 0.4959450662136078 0.738483726978302 0.8885120749473572 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2943.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2943.txt new file mode 100644 index 0000000..ada9028 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2943.txt @@ -0,0 +1,2 @@ +1 0.5031718611717224 0.50135737657547 0.7134458422660828 0.7958742380142212 +0 0.7242938280105591 0.4304577112197876 0.26723921298980713 0.6487724781036377 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2954.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2954.txt new file mode 100644 index 0000000..b456793 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2954.txt @@ -0,0 +1,2 @@ +0 0.7370965480804443 0.5030688643455505 0.27138233184814453 0.3714843988418579 +1 0.3669883608818054 0.5039877891540527 0.3971599042415619 0.35962599515914917 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2973.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2973.txt new file mode 100644 index 0000000..9070f3f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2973.txt @@ -0,0 +1,2 @@ +1 0.5037694573402405 0.4933113157749176 0.1933591365814209 0.9483827352523804 +0 0.06250275671482086 0.499979168176651 0.08103267848491669 0.9410777688026428 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2993.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2993.txt new file mode 100644 index 0000000..fc6a994 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart2993.txt @@ -0,0 +1,2 @@ +0 0.31760188937187195 0.668942928314209 0.41652509570121765 0.31853920221328735 +1 0.7138762474060059 0.49880272150039673 0.3650335371494293 0.6657432913780212 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3014.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3014.txt new file mode 100644 index 0000000..4253d23 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3014.txt @@ -0,0 +1 @@ +1 0.49868443608283997 0.517829418182373 0.7755807042121887 0.34512603282928467 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3023.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3023.txt new file mode 100644 index 0000000..cc8a506 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3023.txt @@ -0,0 +1,2 @@ +1 0.5036799311637878 0.3742596507072449 0.982623815536499 0.7481439113616943 +0 0.7508520483970642 0.5136930346488953 0.4229768216609955 0.29530179500579834 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3034.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3034.txt new file mode 100644 index 0000000..1ce3f6e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3034.txt @@ -0,0 +1 @@ +1 0.48956072330474854 0.4665148854255676 0.9788238406181335 0.7616620659828186 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart304.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart304.txt new file mode 100644 index 0000000..bc0babb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart304.txt @@ -0,0 +1 @@ +1 0.507135272026062 0.483991801738739 0.5647911429405212 0.8497436046600342 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3044.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3044.txt new file mode 100644 index 0000000..8494462 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3044.txt @@ -0,0 +1,2 @@ +0 0.5039952397346497 0.663634717464447 0.3435336649417877 0.49451562762260437 +1 0.5094107389450073 0.2471599280834198 0.6118346452713013 0.23588578402996063 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3053.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3053.txt new file mode 100644 index 0000000..170a80f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3053.txt @@ -0,0 +1,2 @@ +0 0.49284568428993225 0.7590967416763306 0.46453219652175903 0.1773199737071991 +1 0.49322575330734253 0.39947807788848877 0.469852477312088 0.4981544017791748 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3066.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3066.txt new file mode 100644 index 0000000..3303a47 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3066.txt @@ -0,0 +1,2 @@ +1 0.496717631816864 0.45155981183052063 0.9532774686813354 0.8959206342697144 +0 0.7346490621566772 0.6171462535858154 0.4732798933982849 0.47393998503685 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3075.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3075.txt new file mode 100644 index 0000000..2304252 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3075.txt @@ -0,0 +1,2 @@ +1 0.502842903137207 0.3644910454750061 0.9918556213378906 0.7226359844207764 +0 0.4991695284843445 0.8565204739570618 0.991483211517334 0.2759602665901184 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3084.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3084.txt new file mode 100644 index 0000000..0e0e335 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3084.txt @@ -0,0 +1 @@ +1 0.4929001033306122 0.4931977093219757 0.617060124874115 0.8674420118331909 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3094.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3094.txt new file mode 100644 index 0000000..36b2836 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3094.txt @@ -0,0 +1,2 @@ +0 0.6897991299629211 0.5262400507926941 0.5801438093185425 0.25171926617622375 +1 0.20835748314857483 0.5453190803527832 0.32232367992401123 0.650887668132782 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3104.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3104.txt new file mode 100644 index 0000000..a8e26a8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3104.txt @@ -0,0 +1 @@ +0 0.4886876046657562 0.7717201709747314 0.710512101650238 0.11306232959032059 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3113.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3113.txt new file mode 100644 index 0000000..b75677c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3113.txt @@ -0,0 +1,2 @@ +0 0.4987035095691681 0.7161217331886292 0.40655791759490967 0.2534268796443939 +1 0.499576598405838 0.36771145462989807 0.416286826133728 0.42597341537475586 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3123.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3123.txt new file mode 100644 index 0000000..4d04970 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3123.txt @@ -0,0 +1,2 @@ +0 0.7685327529907227 0.49787646532058716 0.24465276300907135 0.5227499008178711 +1 0.3777371048927307 0.5162875056266785 0.5459431409835815 0.395944744348526 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3134.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3134.txt new file mode 100644 index 0000000..4f937ed --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3134.txt @@ -0,0 +1,2 @@ +0 0.49749478697776794 0.25390195846557617 0.6421446800231934 0.19644023478031158 +1 0.4964767396450043 0.5967147350311279 0.6667644381523132 0.49420520663261414 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart314.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart314.txt new file mode 100644 index 0000000..af90516 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart314.txt @@ -0,0 +1,2 @@ +0 0.49932023882865906 0.7334738969802856 0.305297315120697 0.327059268951416 +1 0.4988781213760376 0.3359729051589966 0.30706411600112915 0.47016826272010803 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3154.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3154.txt new file mode 100644 index 0000000..6ab8902 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3154.txt @@ -0,0 +1,2 @@ +1 0.49689027667045593 0.6492021083831787 0.8839457035064697 0.5904135704040527 +1 0.5696132183074951 0.25613102316856384 0.7154753804206848 0.17703978717327118 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3163.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3163.txt new file mode 100644 index 0000000..e41702c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3163.txt @@ -0,0 +1,2 @@ +1 0.5032116174697876 0.4941273331642151 0.9935767650604248 0.984187126159668 +0 0.4430668354034424 0.7283775806427002 0.2777073383331299 0.5124059319496155 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3174.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3174.txt new file mode 100644 index 0000000..5dd6a1c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3174.txt @@ -0,0 +1,3 @@ +0 0.7371692657470703 0.3474596440792084 0.3318796157836914 0.19300350546836853 +1 0.4630223214626312 0.44814741611480713 0.7587255835533142 0.414237380027771 +1 0.32861366868019104 0.4481833577156067 0.48879650235176086 0.4141000509262085 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3185.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3185.txt new file mode 100644 index 0000000..80ac379 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3185.txt @@ -0,0 +1,2 @@ +0 0.684374213218689 0.7975451350212097 0.6292922496795654 0.3939197361469269 +1 0.6853765249252319 0.3054531216621399 0.6292470693588257 0.6109062433242798 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3194.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3194.txt new file mode 100644 index 0000000..1522ceb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3194.txt @@ -0,0 +1,2 @@ +0 0.7079688906669617 0.5061591267585754 0.3374810814857483 0.2929258644580841 +1 0.32509613037109375 0.49310103058815 0.4042345881462097 0.6460144519805908 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3203.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3203.txt new file mode 100644 index 0000000..9ced7bb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3203.txt @@ -0,0 +1,4 @@ +1 0.5001540184020996 0.49253422021865845 0.4411114752292633 0.7152910232543945 +0 0.5003517270088196 0.5365473031997681 0.43837690353393555 0.30365702509880066 +1 0.5017890334129333 0.6019673347473145 0.4414595663547516 0.5137197971343994 +0 0.5001338124275208 0.5473096966743469 0.4387069046497345 0.5177826285362244 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3214.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3214.txt new file mode 100644 index 0000000..703ca60 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3214.txt @@ -0,0 +1,2 @@ +1 0.4890609383583069 0.2925083637237549 0.923782467842102 0.581830620765686 +0 0.482204794883728 0.6869121193885803 0.9296181797981262 0.1981079876422882 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3226.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3226.txt new file mode 100644 index 0000000..1a6dd64 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3226.txt @@ -0,0 +1,2 @@ +0 0.7575685977935791 0.52248615026474 0.435947448015213 0.32050004601478577 +1 0.5015132427215576 0.3968479037284851 0.9955763816833496 0.7608352303504944 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3234.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3234.txt new file mode 100644 index 0000000..d91d781 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3234.txt @@ -0,0 +1 @@ +1 0.7354512810707092 0.4897075593471527 0.4916309714317322 0.9768497347831726 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart324.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart324.txt new file mode 100644 index 0000000..e7cb4d5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart324.txt @@ -0,0 +1,2 @@ +1 0.2737298309803009 0.4968721866607666 0.5473440885543823 0.9937443733215332 +0 0.7724420428276062 0.6439322829246521 0.44882437586784363 0.5739297866821289 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3244.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3244.txt new file mode 100644 index 0000000..50cb205 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3244.txt @@ -0,0 +1,2 @@ +0 0.8242069482803345 0.2747523784637451 0.3281192481517792 0.5091965794563293 +1 0.3362763524055481 0.3425079584121704 0.6725527048110962 0.6531252264976501 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3254.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3254.txt new file mode 100644 index 0000000..3ebe8ec --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3254.txt @@ -0,0 +1 @@ +1 0.49456924200057983 0.5375123620033264 0.9704893827438354 0.47431668639183044 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3263.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3263.txt new file mode 100644 index 0000000..321f66a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3263.txt @@ -0,0 +1,2 @@ +0 0.5026590824127197 0.7216496467590332 0.5529679656028748 0.23655842244625092 +1 0.5027990341186523 0.38456490635871887 0.561759889125824 0.44259920716285706 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3273.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3273.txt new file mode 100644 index 0000000..5c1a866 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3273.txt @@ -0,0 +1,2 @@ +0 0.5017299652099609 0.744364857673645 0.9023975133895874 0.23859122395515442 +1 0.503453254699707 0.3586828112602234 0.8997926115989685 0.5336621403694153 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3284.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3284.txt new file mode 100644 index 0000000..e1107b9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3284.txt @@ -0,0 +1 @@ +1 0.5015450119972229 0.3982227146625519 0.9575356841087341 0.7791057229042053 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3294.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3294.txt new file mode 100644 index 0000000..d729dde --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3294.txt @@ -0,0 +1,2 @@ +0 0.6332785487174988 0.6380508542060852 0.27168989181518555 0.4845685064792633 +1 0.35159265995025635 0.5007956624031067 0.2515704035758972 0.7731216549873352 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart33.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart33.txt new file mode 100644 index 0000000..4bb05a7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart33.txt @@ -0,0 +1 @@ +1 0.503678560256958 0.4798954129219055 0.684393048286438 0.44520726799964905 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3306.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3306.txt new file mode 100644 index 0000000..a32a74d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3306.txt @@ -0,0 +1,2 @@ +0 0.7880121469497681 0.4033483862876892 0.32833707332611084 0.45047006011009216 +1 0.332584023475647 0.5014644861221313 0.5753719210624695 0.6492458581924438 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3314.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3314.txt new file mode 100644 index 0000000..c5c97ac --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3314.txt @@ -0,0 +1,3 @@ +1 0.49692392349243164 0.49745485186576843 0.7912219166755676 0.4571041166782379 +0 0.3546251356601715 0.846125602722168 0.505336582660675 0.23754331469535828 +0 0.9695098400115967 0.1285664588212967 0.0609804168343544 0.2571329176425934 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3326.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3326.txt new file mode 100644 index 0000000..7db9aff --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3326.txt @@ -0,0 +1,2 @@ +1 0.5004211068153381 0.40495234727859497 0.7830623388290405 0.5494125485420227 +0 0.38927751779556274 0.7563810348510742 0.5509557127952576 0.14901086688041687 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3334.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3334.txt new file mode 100644 index 0000000..7395321 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3334.txt @@ -0,0 +1 @@ +1 0.50771564245224 0.5014280676841736 0.9218043684959412 0.1391223967075348 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3344.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3344.txt new file mode 100644 index 0000000..137515c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3344.txt @@ -0,0 +1 @@ +1 0.5111573338508606 0.49568262696266174 0.8480604887008667 0.5555568933486938 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart335.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart335.txt new file mode 100644 index 0000000..52457ee --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart335.txt @@ -0,0 +1,2 @@ +1 0.49038970470428467 0.3184134066104889 0.8230603337287903 0.2696476876735687 +0 0.49099045991897583 0.6709579825401306 0.6239219903945923 0.3761284053325653 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3353.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3353.txt new file mode 100644 index 0000000..6e364a4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3353.txt @@ -0,0 +1 @@ +1 0.4982033669948578 0.5013007521629333 0.695276141166687 0.7452671527862549 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3373.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3373.txt new file mode 100644 index 0000000..693c36e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3373.txt @@ -0,0 +1 @@ +1 0.5056164860725403 0.49008339643478394 0.598508894443512 0.7338908314704895 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3386.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3386.txt new file mode 100644 index 0000000..e85f5c0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3386.txt @@ -0,0 +1,2 @@ +1 0.48190945386886597 0.4606550931930542 0.9575093388557434 0.6793168783187866 +1 0.4767369031906128 0.5942718982696533 0.9211985468864441 0.4221383035182953 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3393.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3393.txt new file mode 100644 index 0000000..27000ef --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3393.txt @@ -0,0 +1,2 @@ +1 0.5000309348106384 0.433380126953125 0.6479365229606628 0.5830217599868774 +0 0.38266831636428833 0.7897430658340454 0.4193856716156006 0.14297078549861908 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3403.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3403.txt new file mode 100644 index 0000000..a915ae8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3403.txt @@ -0,0 +1 @@ +1 0.5001190900802612 0.5 0.9997222423553467 1.0 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3415.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3415.txt new file mode 100644 index 0000000..b7c5c72 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3415.txt @@ -0,0 +1 @@ +1 0.48045581579208374 0.46544575691223145 0.8628945350646973 0.6493343710899353 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3424.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3424.txt new file mode 100644 index 0000000..dbb974b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3424.txt @@ -0,0 +1,2 @@ +1 0.5008981227874756 0.4447302222251892 0.43031010031700134 0.6142120957374573 +0 0.45852378010749817 0.8050678968429565 0.3376826047897339 0.10883026570081711 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3433.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3433.txt new file mode 100644 index 0000000..a8000d5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3433.txt @@ -0,0 +1 @@ +1 0.49867093563079834 0.4995727837085724 0.6159147024154663 0.7624191641807556 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart344.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart344.txt new file mode 100644 index 0000000..5e1d2af --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart344.txt @@ -0,0 +1,2 @@ +0 0.49473488330841064 0.732779324054718 0.4831555187702179 0.40151771903038025 +1 0.48537662625312805 0.31822022795677185 0.4797747731208801 0.41899949312210083 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3443.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3443.txt new file mode 100644 index 0000000..d1f21d2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3443.txt @@ -0,0 +1,2 @@ +1 0.5022664666175842 0.4044652283191681 0.6317052245140076 0.5312997102737427 +0 0.4111008048057556 0.7482869625091553 0.4623554050922394 0.16144277155399323 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3453.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3453.txt new file mode 100644 index 0000000..ad94fae --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3453.txt @@ -0,0 +1 @@ +1 0.49852246046066284 0.4982505440711975 0.9969847798347473 0.996501088142395 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3465.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3465.txt new file mode 100644 index 0000000..08ecd56 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3465.txt @@ -0,0 +1 @@ +1 0.5030645728111267 0.4877539873123169 0.9718249440193176 0.9534922242164612 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3476.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3476.txt new file mode 100644 index 0000000..d131a36 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3476.txt @@ -0,0 +1 @@ +1 0.48525333404541016 0.5067318677902222 0.7892099618911743 0.8312041163444519 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3484.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3484.txt new file mode 100644 index 0000000..b69769e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3484.txt @@ -0,0 +1,2 @@ +1 0.5011677742004395 0.49906861782073975 0.5668718814849854 0.7032356858253479 +0 0.4396172761917114 0.647516131401062 0.43639814853668213 0.16546383500099182 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3496.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3496.txt new file mode 100644 index 0000000..7c4a898 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3496.txt @@ -0,0 +1 @@ +1 0.49402713775634766 0.47433149814605713 0.9526047110557556 0.546690821647644 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3504.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3504.txt new file mode 100644 index 0000000..260c789 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3504.txt @@ -0,0 +1,2 @@ +1 0.5125536918640137 0.37894171476364136 0.277371883392334 0.5615121126174927 +0 0.5139692425727844 0.7807565331459045 0.271622896194458 0.24354420602321625 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart35110.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart35110.txt new file mode 100644 index 0000000..db21408 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart35110.txt @@ -0,0 +1 @@ +1 0.49494868516921997 0.41384387016296387 0.9064115285873413 0.4884321093559265 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3526.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3526.txt new file mode 100644 index 0000000..0222bf9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3526.txt @@ -0,0 +1 @@ +1 0.48506230115890503 0.4794096350669861 0.8166724443435669 0.5469229817390442 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3535.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3535.txt new file mode 100644 index 0000000..b471659 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3535.txt @@ -0,0 +1 @@ +1 0.4828033149242401 0.49458298087120056 0.9613819718360901 0.9891659617424011 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart354.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart354.txt new file mode 100644 index 0000000..b0ac152 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart354.txt @@ -0,0 +1,2 @@ +1 0.4981854557991028 0.38043758273124695 0.7575616836547852 0.2649077773094177 +0 0.7119038701057434 0.6488344669342041 0.3427273631095886 0.22703072428703308 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3543.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3543.txt new file mode 100644 index 0000000..85d9673 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3543.txt @@ -0,0 +1,2 @@ +0 0.8007397055625916 0.49701783061027527 0.3872353434562683 0.9732649922370911 +1 0.30383965373039246 0.4979707598686218 0.6052893996238708 0.9792742133140564 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3553.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3553.txt new file mode 100644 index 0000000..bc7aa4a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3553.txt @@ -0,0 +1,2 @@ +0 0.8147715330123901 0.34408530592918396 0.36899861693382263 0.6815034747123718 +1 0.3195129334926605 0.4984019994735718 0.6256357431411743 0.9882475137710571 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3563.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3563.txt new file mode 100644 index 0000000..410cc7f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3563.txt @@ -0,0 +1 @@ +1 0.5065785646438599 0.501312255859375 0.9228976368904114 0.13890784978866577 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3575.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3575.txt new file mode 100644 index 0000000..31cf93f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3575.txt @@ -0,0 +1 @@ +1 0.5294966697692871 0.4975542724132538 0.8117309212684631 0.8967428207397461 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3586.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3586.txt new file mode 100644 index 0000000..73cf36a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3586.txt @@ -0,0 +1 @@ +1 0.4983442425727844 0.5079566240310669 0.8236272931098938 0.7860673666000366 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3596.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3596.txt new file mode 100644 index 0000000..0054b0d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3596.txt @@ -0,0 +1,2 @@ +1 0.4926074743270874 0.42801326513290405 0.6182782649993896 0.5717326402664185 +0 0.3814845085144043 0.7760031819343567 0.40195611119270325 0.13493627309799194 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3607.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3607.txt new file mode 100644 index 0000000..f6bed6d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3607.txt @@ -0,0 +1,4 @@ +0 0.7159242033958435 0.6879308223724365 0.22429747879505157 0.2860468029975891 +0 0.7162349224090576 0.15440386533737183 0.22396142780780792 0.2608684003353119 +1 0.5006741881370544 0.7673574090003967 0.6589974761009216 0.4414450526237488 +1 0.5041871666908264 0.28912249207496643 0.6603975892066956 0.5188169479370117 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3614.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3614.txt new file mode 100644 index 0000000..1765893 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3614.txt @@ -0,0 +1 @@ +1 0.49835601449012756 0.4998891353607178 0.7049081325531006 0.2689308524131775 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3624.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3624.txt new file mode 100644 index 0000000..0c87abe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3624.txt @@ -0,0 +1 @@ +1 0.5008895993232727 0.4915105998516083 0.6875073909759521 0.5153179168701172 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3634.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3634.txt new file mode 100644 index 0000000..ff012a5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3634.txt @@ -0,0 +1 @@ +1 0.5040339827537537 0.5225005745887756 0.713523268699646 0.6513434648513794 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart364.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart364.txt new file mode 100644 index 0000000..2335776 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart364.txt @@ -0,0 +1,2 @@ +0 0.279433012008667 0.4937437176704407 0.41942617297172546 0.7101032137870789 +1 0.7136660814285278 0.5057042241096497 0.4091190993785858 0.7786241173744202 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3644.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3644.txt new file mode 100644 index 0000000..d481407 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3644.txt @@ -0,0 +1 @@ +1 0.49660617113113403 0.48670002818107605 0.7657232880592346 0.8592946529388428 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3654.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3654.txt new file mode 100644 index 0000000..767eb59 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3654.txt @@ -0,0 +1 @@ +1 0.4994848370552063 0.5183745622634888 0.6876682639122009 0.517598569393158 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3665.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3665.txt new file mode 100644 index 0000000..dff0563 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3665.txt @@ -0,0 +1 @@ +1 0.4837459921836853 0.4906034767627716 0.787614107131958 0.7820314168930054 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3674.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3674.txt new file mode 100644 index 0000000..aea2428 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3674.txt @@ -0,0 +1,2 @@ +0 0.6945149302482605 0.5632027983665466 0.39462730288505554 0.15976403653621674 +1 0.4956575036048889 0.5029487609863281 0.7968637347221375 0.2950187623500824 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3694.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3694.txt new file mode 100644 index 0000000..ae1f2a9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3694.txt @@ -0,0 +1 @@ +1 0.5082937479019165 0.4829823970794678 0.7342262864112854 0.842536211013794 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3713.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3713.txt new file mode 100644 index 0000000..2544d52 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3713.txt @@ -0,0 +1 @@ +1 0.5024575591087341 0.499478280544281 0.7474164962768555 0.3953985273838043 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3724.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3724.txt new file mode 100644 index 0000000..a79c093 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3724.txt @@ -0,0 +1 @@ +1 0.4981327950954437 0.5325356721878052 0.563211977481842 0.25107595324516296 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3734.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3734.txt new file mode 100644 index 0000000..7fb76d2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3734.txt @@ -0,0 +1 @@ +1 0.520281195640564 0.48366692662239075 0.6381749510765076 0.5560811161994934 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3743.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3743.txt new file mode 100644 index 0000000..c9de599 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3743.txt @@ -0,0 +1 @@ +1 0.5133043527603149 0.5075891017913818 0.8796108961105347 0.8570425510406494 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3754.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3754.txt new file mode 100644 index 0000000..3ffa554 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3754.txt @@ -0,0 +1 @@ +1 0.49184650182724 0.49340033531188965 0.630750298500061 0.6669607162475586 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3763.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3763.txt new file mode 100644 index 0000000..486d6cc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3763.txt @@ -0,0 +1 @@ +1 0.49935027956962585 0.49846187233924866 0.7757826447486877 0.787989616394043 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3774.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3774.txt new file mode 100644 index 0000000..252a4bf --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3774.txt @@ -0,0 +1 @@ +1 0.5062710046768188 0.49600961804389954 0.849567174911499 0.6611877083778381 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3783.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3783.txt new file mode 100644 index 0000000..4398904 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3783.txt @@ -0,0 +1 @@ +1 0.4969872832298279 0.4899310767650604 0.8541231751441956 0.7659209370613098 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3794.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3794.txt new file mode 100644 index 0000000..77b9f59 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3794.txt @@ -0,0 +1,2 @@ +0 0.4331929087638855 0.6579374670982361 0.5301385521888733 0.17022362351417542 +1 0.5494025945663452 0.39601486921310425 0.4904511570930481 0.282511830329895 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3804.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3804.txt new file mode 100644 index 0000000..3dab2f8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3804.txt @@ -0,0 +1 @@ +1 0.5053142309188843 0.48736289143562317 0.8085072040557861 0.863480806350708 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3814.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3814.txt new file mode 100644 index 0000000..2a3ddc0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3814.txt @@ -0,0 +1 @@ +1 0.4999467134475708 0.4949967563152313 0.7721118927001953 0.16076387465000153 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3824.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3824.txt new file mode 100644 index 0000000..bb46145 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3824.txt @@ -0,0 +1 @@ +1 0.505757212638855 0.4942164421081543 0.589812695980072 0.8008952140808105 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3834.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3834.txt new file mode 100644 index 0000000..86628a1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3834.txt @@ -0,0 +1 @@ +1 0.49023792147636414 0.4637295603752136 0.6754675507545471 0.7491400837898254 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3844.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3844.txt new file mode 100644 index 0000000..9b28120 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3844.txt @@ -0,0 +1 @@ +1 0.49644842743873596 0.5005249977111816 0.6021914482116699 0.4493177533149719 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3855.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3855.txt new file mode 100644 index 0000000..ced0be8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3855.txt @@ -0,0 +1,4 @@ +0 0.5779913663864136 0.44572713971138 0.4978168308734894 0.17678070068359375 +0 0.44598039984703064 0.8020789623260498 0.40551891922950745 0.1478969305753708 +1 0.5212687253952026 0.32688018679618835 0.632576584815979 0.4242766499519348 +1 0.5313119888305664 0.7092006802558899 0.5763539671897888 0.3426355719566345 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3863.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3863.txt new file mode 100644 index 0000000..cb9f6f5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3863.txt @@ -0,0 +1 @@ +1 0.4999524652957916 0.5031164884567261 0.9978464245796204 0.9937671422958374 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3875.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3875.txt new file mode 100644 index 0000000..6e00a00 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3875.txt @@ -0,0 +1 @@ +1 0.4992291033267975 0.8311979174613953 0.9942449331283569 0.3376040756702423 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3904.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3904.txt new file mode 100644 index 0000000..ed21363 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart3904.txt @@ -0,0 +1 @@ +1 0.5002242922782898 0.49817222356796265 0.6305814981460571 0.20742496848106384 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart394.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart394.txt new file mode 100644 index 0000000..b0e628d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart394.txt @@ -0,0 +1,2 @@ +1 0.3886120617389679 0.4980592727661133 0.5748487114906311 0.2033034712076187 +0 0.7849981188774109 0.49780982732772827 0.22468110918998718 0.20788587629795074 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart404.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart404.txt new file mode 100644 index 0000000..e507e5c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart404.txt @@ -0,0 +1,2 @@ +1 0.34722158312797546 0.5115203261375427 0.40489259362220764 0.4829244911670685 +0 0.7224182486534119 0.5658107399940491 0.24907411634922028 0.35811376571655273 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart414.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart414.txt new file mode 100644 index 0000000..44b947d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart414.txt @@ -0,0 +1,2 @@ +0 0.7545275688171387 0.6925899386405945 0.4500821530818939 0.6138522028923035 +1 0.22622738778591156 0.5755565762519836 0.4506119191646576 0.8243402242660522 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart426.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart426.txt new file mode 100644 index 0000000..bf17227 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart426.txt @@ -0,0 +1,2 @@ +1 0.6813719272613525 0.49107667803764343 0.39239010214805603 0.8300564289093018 +0 0.23463128507137299 0.4461088478565216 0.34875810146331787 0.48201531171798706 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart43.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart43.txt new file mode 100644 index 0000000..921923b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart43.txt @@ -0,0 +1,2 @@ +1 0.5003324747085571 0.31725290417671204 0.7549957633018494 0.2859555184841156 +1 0.5020873546600342 0.6516724228858948 0.7060255408287048 0.3473617732524872 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart433.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart433.txt new file mode 100644 index 0000000..92c5d14 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart433.txt @@ -0,0 +1,2 @@ +0 0.7051307559013367 0.42541563510894775 0.3456730246543884 0.3757795989513397 +1 0.31492236256599426 0.4750770032405853 0.404727965593338 0.46375200152397156 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart443.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart443.txt new file mode 100644 index 0000000..f58b5ae --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart443.txt @@ -0,0 +1,2 @@ +1 0.4967406392097473 0.3660619854927063 0.37327954173088074 0.5405624508857727 +0 0.49954384565353394 0.7745351195335388 0.4363895654678345 0.2602164149284363 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart453.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart453.txt new file mode 100644 index 0000000..40053cd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart453.txt @@ -0,0 +1,2 @@ +0 0.3188515603542328 0.5006822347640991 0.31373459100723267 0.5590912103652954 +1 0.6712008714675903 0.5268482565879822 0.3295511305332184 0.5049919486045837 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart464.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart464.txt new file mode 100644 index 0000000..260df5e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart464.txt @@ -0,0 +1,3 @@ +0 0.31132566928863525 0.5723105669021606 0.48902538418769836 0.1612478345632553 +1 0.4954685568809509 0.5048827528953552 0.8543678522109985 0.301844984292984 +1 0.496500164270401 0.4501325786113739 0.8555222153663635 0.19210952520370483 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart474.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart474.txt new file mode 100644 index 0000000..6df1f01 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart474.txt @@ -0,0 +1,2 @@ +0 0.8065941333770752 0.5039182901382446 0.30640026926994324 0.3700295090675354 +1 0.3511298894882202 0.496898353099823 0.6143314242362976 0.3854747712612152 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart484.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart484.txt new file mode 100644 index 0000000..7826f18 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart484.txt @@ -0,0 +1,2 @@ +1 0.4934253394603729 0.2906554937362671 0.9254430532455444 0.28742092847824097 +0 0.6433565616607666 0.6484841108322144 0.6045243740081787 0.40158042311668396 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart494.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart494.txt new file mode 100644 index 0000000..61074a3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart494.txt @@ -0,0 +1,2 @@ +1 0.3915521800518036 0.48428967595100403 0.5458637475967407 0.2729892134666443 +0 0.7690156698226929 0.4816204309463501 0.21024419367313385 0.27026140689849854 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart504.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart504.txt new file mode 100644 index 0000000..bd8759e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart504.txt @@ -0,0 +1,2 @@ +1 0.30361586809158325 0.5026242733001709 0.5654603838920593 0.33660659193992615 +0 0.7810460329055786 0.5006259083747864 0.40262287855148315 0.3420543670654297 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart515.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart515.txt new file mode 100644 index 0000000..946c380 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart515.txt @@ -0,0 +1,2 @@ +0 0.6876540184020996 0.5394195914268494 0.31769171357154846 0.3433926999568939 +1 0.2952955365180969 0.49022936820983887 0.340619295835495 0.6806798577308655 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart524.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart524.txt new file mode 100644 index 0000000..454f752 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart524.txt @@ -0,0 +1,2 @@ +0 0.5016622543334961 0.5750165581703186 0.6079878807067871 0.1982538253068924 +1 0.5016782879829407 0.40835556387901306 0.610273003578186 0.1082979291677475 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart544.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart544.txt new file mode 100644 index 0000000..250faee --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart544.txt @@ -0,0 +1,2 @@ +1 0.3533551096916199 0.4957767724990845 0.4953765869140625 0.26463204622268677 +0 0.7493613958358765 0.44960322976112366 0.28666651248931885 0.17147357761859894 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart554.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart554.txt new file mode 100644 index 0000000..3ac0dd5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart554.txt @@ -0,0 +1,2 @@ +0 0.6793172955513 0.6875921487808228 0.3268425166606903 0.3544670343399048 +1 0.3430987000465393 0.507409930229187 0.3487212657928467 0.7276381850242615 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart564.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart564.txt new file mode 100644 index 0000000..c8993ee --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart564.txt @@ -0,0 +1,2 @@ +0 0.4924904704093933 0.6815304756164551 0.39134618639945984 0.5793840289115906 +1 0.4842504560947418 0.2258080393075943 0.9401374459266663 0.30734768509864807 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart574.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart574.txt new file mode 100644 index 0000000..5762f56 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart574.txt @@ -0,0 +1,2 @@ +0 0.49595919251441956 0.7165109515190125 0.24438436329364777 0.2985686659812927 +1 0.48786461353302 0.34152108430862427 0.2697233259677887 0.44668811559677124 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart583.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart583.txt new file mode 100644 index 0000000..b7d65f6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart583.txt @@ -0,0 +1,2 @@ +0 0.3079499304294586 0.6848356127738953 0.3445415794849396 0.30135175585746765 +1 0.6757595539093018 0.4956403970718384 0.379459947347641 0.6698143482208252 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart594.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart594.txt new file mode 100644 index 0000000..8569666 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart594.txt @@ -0,0 +1,2 @@ +0 0.6775968074798584 0.520362377166748 0.29169490933418274 0.48484107851982117 +1 0.31561195850372314 0.5121009945869446 0.3360668420791626 0.5420042276382446 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart606.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart606.txt new file mode 100644 index 0000000..dd06d6b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart606.txt @@ -0,0 +1,2 @@ +1 0.6820791959762573 0.48034635186195374 0.3813993036746979 0.8253171443939209 +0 0.251321405172348 0.46989402174949646 0.3407605290412903 0.4438246488571167 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart613.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart613.txt new file mode 100644 index 0000000..555cab9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart613.txt @@ -0,0 +1,2 @@ +0 0.4969189465045929 0.7691493630409241 0.7718390822410583 0.21160927414894104 +1 0.4957868754863739 0.3921663761138916 0.7730465531349182 0.5360782146453857 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart624.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart624.txt new file mode 100644 index 0000000..2f0e1f0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart624.txt @@ -0,0 +1,2 @@ +1 0.5027472972869873 0.4121805429458618 0.6260594725608826 0.5463917255401611 +0 0.35882920026779175 0.7706176042556763 0.34841421246528625 0.1739654690027237 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart636.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart636.txt new file mode 100644 index 0000000..ae7adb1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart636.txt @@ -0,0 +1 @@ +1 0.5091351270675659 0.5041216015815735 0.9754285216331482 0.8760802745819092 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart64.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart64.txt new file mode 100644 index 0000000..20cdf26 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart64.txt @@ -0,0 +1,2 @@ +1 0.5011151432991028 0.4312753677368164 0.7804595232009888 0.309962660074234 +0 0.3120451271533966 0.6465304493904114 0.4045105278491974 0.13172297179698944 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart644.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart644.txt new file mode 100644 index 0000000..5663e54 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart644.txt @@ -0,0 +1,2 @@ +0 0.496498703956604 0.7638238668441772 0.6693745255470276 0.14827856421470642 +1 0.5024042129516602 0.41208547353744507 0.2554170787334442 0.5093984603881836 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart653.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart653.txt new file mode 100644 index 0000000..b3d0024 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart653.txt @@ -0,0 +1,2 @@ +0 0.3944569230079651 0.7600647807121277 0.4452749490737915 0.17777419090270996 +1 0.4881496727466583 0.3907714784145355 0.6386116147041321 0.5607782602310181 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart664.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart664.txt new file mode 100644 index 0000000..e242738 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart664.txt @@ -0,0 +1,2 @@ +1 0.5035348534584045 0.4478839337825775 0.7555696368217468 0.33947184681892395 +0 0.5015339255332947 0.6694806218147278 0.74776691198349 0.10916329175233841 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart674.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart674.txt new file mode 100644 index 0000000..4f07c58 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart674.txt @@ -0,0 +1,2 @@ +1 0.3376000225543976 0.48125579953193665 0.4328024685382843 0.3367473781108856 +0 0.7126524448394775 0.44647130370140076 0.3085755705833435 0.1382877677679062 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart685.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart685.txt new file mode 100644 index 0000000..c151fee --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart685.txt @@ -0,0 +1,2 @@ +1 0.49222859740257263 0.49485108256340027 0.7772773504257202 0.7602454423904419 +0 0.3014332354068756 0.857671856880188 0.3796852231025696 0.05539150536060333 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart694.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart694.txt new file mode 100644 index 0000000..b7b8bb7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart694.txt @@ -0,0 +1,2 @@ +0 0.5029105544090271 0.7640315890312195 0.5595418810844421 0.21209527552127838 +1 0.5021198987960815 0.39418014883995056 0.5580766201019287 0.5099360942840576 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart704.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart704.txt new file mode 100644 index 0000000..6a1e9ed --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart704.txt @@ -0,0 +1,2 @@ +0 0.49706050753593445 0.6400842070579529 0.48625192046165466 0.33140814304351807 +1 0.4895462691783905 0.32597532868385315 0.764781653881073 0.2875124216079712 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart714.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart714.txt new file mode 100644 index 0000000..b6dcc06 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart714.txt @@ -0,0 +1 @@ +1 0.5060369968414307 0.49665772914886475 0.4432130753993988 0.5875710844993591 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart724.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart724.txt new file mode 100644 index 0000000..ea0c016 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart724.txt @@ -0,0 +1,2 @@ +1 0.4986262917518616 0.43836456537246704 0.5870899558067322 0.4284675717353821 +0 0.42858263850212097 0.7228182554244995 0.44752639532089233 0.14509887993335724 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart733.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart733.txt new file mode 100644 index 0000000..394db6f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart733.txt @@ -0,0 +1 @@ +1 0.498735636472702 0.4466935694217682 0.5656067132949829 0.6699326038360596 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart744.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart744.txt new file mode 100644 index 0000000..b211682 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart744.txt @@ -0,0 +1,2 @@ +0 0.31071752309799194 0.6954023838043213 0.4562096893787384 0.231636181473732 +1 0.4203293025493622 0.5063376426696777 0.6863210201263428 0.6112619638442993 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart753.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart753.txt new file mode 100644 index 0000000..ac1a909 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart753.txt @@ -0,0 +1,2 @@ +0 0.729847252368927 0.37766191363334656 0.3405087888240814 0.269457072019577 +1 0.5008068084716797 0.5024471282958984 0.7823372483253479 0.5150808095932007 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart765.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart765.txt new file mode 100644 index 0000000..5c81f4c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart765.txt @@ -0,0 +1,2 @@ +1 0.39257222414016724 0.47369423508644104 0.5425431728363037 0.348580002784729 +0 0.7735805511474609 0.47116777300834656 0.22464613616466522 0.34322765469551086 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart774.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart774.txt new file mode 100644 index 0000000..8cd1c74 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart774.txt @@ -0,0 +1,2 @@ +0 0.7925764322280884 0.4829067289829254 0.37316593527793884 0.5712701678276062 +1 0.4999946653842926 0.4426303505897522 0.9940667748451233 0.8061715364456177 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart785.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart785.txt new file mode 100644 index 0000000..69fc6d1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart785.txt @@ -0,0 +1,2 @@ +1 0.5047963261604309 0.38832080364227295 0.6566255688667297 0.5649795532226562 +0 0.5048568844795227 0.7825304269790649 0.6522122025489807 0.24180616438388824 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart794.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart794.txt new file mode 100644 index 0000000..3d4aa60 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart794.txt @@ -0,0 +1,2 @@ +1 0.3809354901313782 0.5008120536804199 0.43511447310447693 0.6694956421852112 +0 0.7153893113136292 0.361974835395813 0.2399396449327469 0.3833025097846985 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart805.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart805.txt new file mode 100644 index 0000000..1aca616 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart805.txt @@ -0,0 +1,2 @@ +0 0.759331226348877 0.35598546266555786 0.2532477080821991 0.3616846799850464 +1 0.382630318403244 0.49788907170295715 0.4991772174835205 0.6494772434234619 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart815.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart815.txt new file mode 100644 index 0000000..3f68662 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart815.txt @@ -0,0 +1,2 @@ +1 0.4948813319206238 0.3791498839855194 0.6305972337722778 0.29004767537117004 +0 0.3592613935470581 0.6377294063568115 0.36102092266082764 0.16835080087184906 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart824.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart824.txt new file mode 100644 index 0000000..c57855c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart824.txt @@ -0,0 +1,2 @@ +1 0.5053467154502869 0.504288911819458 0.6838799118995667 0.5249482989311218 +0 0.7419264912605286 0.6059873700141907 0.19343282282352448 0.31338974833488464 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart834.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart834.txt new file mode 100644 index 0000000..9c390ec --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart834.txt @@ -0,0 +1,2 @@ +0 0.4999999701976776 0.8608675003051758 0.9999999403953552 0.2752704620361328 +1 0.4998556077480316 0.3644692301750183 0.9981592893600464 0.7148343920707703 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart84.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart84.txt new file mode 100644 index 0000000..283c7f9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart84.txt @@ -0,0 +1 @@ +1 0.49106523394584656 0.48766565322875977 0.8048828840255737 0.48592859506607056 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart845.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart845.txt new file mode 100644 index 0000000..26786b9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart845.txt @@ -0,0 +1 @@ +1 0.4963376224040985 0.4944152534008026 0.7807551026344299 0.4697240889072418 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart854.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart854.txt new file mode 100644 index 0000000..4c1fbca --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart854.txt @@ -0,0 +1 @@ +1 0.501654863357544 0.5114012360572815 0.7306572198867798 0.2960100471973419 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart864.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart864.txt new file mode 100644 index 0000000..78c7ab1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart864.txt @@ -0,0 +1,2 @@ +1 0.4990449845790863 0.4092046320438385 0.639604926109314 0.5791117548942566 +0 0.36398807168006897 0.7815124988555908 0.36968985199928284 0.17599837481975555 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart874.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart874.txt new file mode 100644 index 0000000..0b20634 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart874.txt @@ -0,0 +1 @@ +1 0.4994891285896301 0.4981827735900879 0.6528502106666565 0.49906882643699646 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart886.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart886.txt new file mode 100644 index 0000000..91cd4bc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart886.txt @@ -0,0 +1 @@ +1 0.5040255188941956 0.5148044228553772 0.5902116894721985 0.7360053658485413 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart894.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart894.txt new file mode 100644 index 0000000..95513ad --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart894.txt @@ -0,0 +1,2 @@ +1 0.4972195029258728 0.36907482147216797 0.9448015689849854 0.7349424362182617 +0 0.5018018484115601 0.8601139783859253 0.9205582141876221 0.26290345191955566 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart904.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart904.txt new file mode 100644 index 0000000..01be576 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart904.txt @@ -0,0 +1,2 @@ +1 0.4021068811416626 0.49938347935676575 0.45670053362846375 0.2540370523929596 +0 0.7285280823707581 0.4633283317089081 0.2014838010072708 0.18121996521949768 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart915.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart915.txt new file mode 100644 index 0000000..bf514e3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart915.txt @@ -0,0 +1,2 @@ +0 0.4905042052268982 0.8201455473899841 0.36839303374290466 0.1493709683418274 +1 0.4913979470729828 0.41698116064071655 0.3662036657333374 0.6304886341094971 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart924.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart924.txt new file mode 100644 index 0000000..63da925 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart924.txt @@ -0,0 +1,2 @@ +1 0.5071060061454773 0.5061460733413696 0.7279899716377258 0.5525250434875488 +0 0.7100765705108643 0.7052940726280212 0.31178292632102966 0.15342752635478973 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart955.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart955.txt new file mode 100644 index 0000000..6596fe7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart955.txt @@ -0,0 +1,2 @@ +0 0.6484988331794739 0.43981724977493286 0.2793291211128235 0.3201623857021332 +1 0.3501172959804535 0.5017918944358826 0.30867800116539 0.8091660141944885 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart96.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart96.txt new file mode 100644 index 0000000..a3e511b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart96.txt @@ -0,0 +1,2 @@ +1 0.49970096349716187 0.3317369818687439 0.9963085651397705 0.6634739637374878 +0 0.3657175600528717 0.8231520652770996 0.72995525598526 0.34056535363197327 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart975.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart975.txt new file mode 100644 index 0000000..7f16be9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart975.txt @@ -0,0 +1 @@ +1 0.3870176374912262 0.5135340094566345 0.7212493419647217 0.9328876733779907 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart984.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart984.txt new file mode 100644 index 0000000..522577d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart984.txt @@ -0,0 +1 @@ +1 0.5163930654525757 0.5433691740036011 0.75119948387146 0.38567954301834106 diff --git a/models/nutrition_ingredients_information/data/YOLO/output/labels/emart994.txt b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart994.txt new file mode 100644 index 0000000..c9ef9a9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/output/labels/emart994.txt @@ -0,0 +1 @@ +1 0.4957421123981476 0.5064516663551331 0.9901340007781982 0.9462971091270447 diff --git a/models/nutrition_ingredients_information/data/YOLO/train/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/train/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/train/images/.gitkeep b/models/nutrition_ingredients_information/data/YOLO/train/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1003.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1003.txt new file mode 100644 index 0000000..b492b22 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1003.txt @@ -0,0 +1,2 @@ +0 0.501050 0.799748 0.426952 0.186398 +1 0.501050 0.402393 0.421914 0.603275 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1014.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1014.txt new file mode 100644 index 0000000..5ea9116 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1014.txt @@ -0,0 +1,2 @@ +0 0.741082 0.761335 0.496243 0.232997 +1 0.502011 0.443325 0.992485 0.881612 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1023.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1023.txt new file mode 100644 index 0000000..75ce0d1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1023.txt @@ -0,0 +1,2 @@ +0 0.703820 0.789673 0.353904 0.198992 +1 0.319060 0.501259 0.395466 0.790932 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1036.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1036.txt new file mode 100644 index 0000000..339ff0f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1036.txt @@ -0,0 +1,2 @@ +0 0.214399 0.788413 0.428797 0.395466 +1 0.498961 0.302897 0.994762 0.598237 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart104.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart104.txt new file mode 100644 index 0000000..ebf411e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart104.txt @@ -0,0 +1 @@ +1 0.499790 0.516373 0.646096 0.481108 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1044.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1044.txt new file mode 100644 index 0000000..f23b8df --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1044.txt @@ -0,0 +1,2 @@ +0 0.393997 0.700882 0.532746 0.180101 +1 0.501679 0.410579 0.748111 0.413098 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1054.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1054.txt new file mode 100644 index 0000000..8959ee1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1054.txt @@ -0,0 +1,2 @@ +0 0.772687 0.729849 0.454625 0.248111 +1 0.500405 0.448992 0.996624 0.890428 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1064.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1064.txt new file mode 100644 index 0000000..49272d2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1064.txt @@ -0,0 +1 @@ +1 0.499835 0.503953 0.993083 0.984980 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1073.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1073.txt new file mode 100644 index 0000000..971851b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1073.txt @@ -0,0 +1,2 @@ +0 0.825428 0.200794 0.175889 0.270764 +1 0.480567 0.635382 0.794466 0.593861 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1085.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1085.txt new file mode 100644 index 0000000..c7734b7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1085.txt @@ -0,0 +1,2 @@ +0 0.499790 0.168766 0.353904 0.249370 +1 0.499790 0.639169 0.497481 0.613350 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1096.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1096.txt new file mode 100644 index 0000000..5abc204 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1096.txt @@ -0,0 +1,2 @@ +0 0.499160 0.816751 0.460957 0.280856 +1 0.494752 0.353275 0.623426 0.646096 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart114.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart114.txt new file mode 100644 index 0000000..3e7cfdb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart114.txt @@ -0,0 +1,2 @@ +0 0.499160 0.680101 0.783375 0.148615 +1 0.499160 0.428841 0.788413 0.363980 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1156.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1156.txt new file mode 100644 index 0000000..e698252 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1156.txt @@ -0,0 +1,2 @@ +0 0.503325 0.873426 0.992666 0.253148 +1 0.505820 0.372796 0.987678 0.743073 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1163.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1163.txt new file mode 100644 index 0000000..bf9480d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1163.txt @@ -0,0 +1,2 @@ +0 0.665407 0.655542 0.261965 0.348866 +1 0.394626 0.494962 0.272040 0.654912 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1174.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1174.txt new file mode 100644 index 0000000..6b21808 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1174.txt @@ -0,0 +1,2 @@ +0 0.677372 0.498111 0.361461 0.338791 +1 0.319689 0.455919 0.326196 0.690176 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1184.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1184.txt new file mode 100644 index 0000000..2369a87 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1184.txt @@ -0,0 +1,2 @@ +0 0.769311 0.605793 0.260705 0.322418 +1 0.359992 0.500630 0.542821 0.832494 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1194.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1194.txt new file mode 100644 index 0000000..0ab0c3d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1194.txt @@ -0,0 +1,2 @@ +0 0.673594 0.567380 0.361461 0.134761 +1 0.502939 0.500630 0.705290 0.265743 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1204.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1204.txt new file mode 100644 index 0000000..a090177 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1204.txt @@ -0,0 +1,2 @@ +0 0.688707 0.569270 0.419395 0.244332 +1 0.509866 0.512594 0.779597 0.362720 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1214.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1214.txt new file mode 100644 index 0000000..9bd10fd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1214.txt @@ -0,0 +1,2 @@ +0 0.325357 0.577456 0.410579 0.492443 +1 0.712007 0.488665 0.309824 0.707809 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1224.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1224.txt new file mode 100644 index 0000000..690bbe8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1224.txt @@ -0,0 +1,2 @@ +0 0.489085 0.773300 0.609572 0.206549 +1 0.494752 0.391058 0.608312 0.560453 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1234.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1234.txt new file mode 100644 index 0000000..bd24db3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1234.txt @@ -0,0 +1,2 @@ +0 0.501050 0.778967 0.560453 0.202771 +1 0.497271 0.405542 0.552897 0.551637 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1243.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1243.txt new file mode 100644 index 0000000..1fa3a75 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1243.txt @@ -0,0 +1,2 @@ +0 0.642737 0.403652 0.279597 0.316121 +1 0.484047 0.493073 0.586902 0.517632 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1253.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1253.txt new file mode 100644 index 0000000..3926e5c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1253.txt @@ -0,0 +1,2 @@ +0 0.689337 0.653652 0.372796 0.327456 +1 0.324727 0.511335 0.318640 0.617128 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1266.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1266.txt new file mode 100644 index 0000000..80aaefe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1266.txt @@ -0,0 +1,2 @@ +0 0.504198 0.727330 0.355164 0.484887 +1 0.499160 0.263224 0.798489 0.408060 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1274.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1274.txt new file mode 100644 index 0000000..c65b233 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1274.txt @@ -0,0 +1 @@ +1 0.482788 0.507557 0.450882 0.405542 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1296.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1296.txt new file mode 100644 index 0000000..e1c7f10 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1296.txt @@ -0,0 +1,2 @@ +0 0.502309 0.817380 0.636020 0.191436 +1 0.504828 0.406801 0.636020 0.637280 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1307.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1307.txt new file mode 100644 index 0000000..d43cf80 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1307.txt @@ -0,0 +1,2 @@ +0 0.501050 0.812343 0.711587 0.231738 +1 0.500420 0.384131 0.715365 0.622166 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1313.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1313.txt new file mode 100644 index 0000000..85f2f6e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1313.txt @@ -0,0 +1,2 @@ +0 0.651553 0.566121 0.423174 0.112091 +1 0.507347 0.522670 0.719144 0.216625 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1337.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1337.txt new file mode 100644 index 0000000..b6eeb13 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1337.txt @@ -0,0 +1,2 @@ +0 0.497901 0.226071 0.498741 0.301008 +1 0.499790 0.675063 0.734257 0.501259 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1344.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1344.txt new file mode 100644 index 0000000..872162f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1344.txt @@ -0,0 +1,2 @@ +0 0.744752 0.544710 0.420655 0.326196 +1 0.243493 0.477960 0.418136 0.421914 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1355.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1355.txt new file mode 100644 index 0000000..80b5e00 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1355.txt @@ -0,0 +1,2 @@ +0 0.626994 0.529597 0.288413 0.391688 +1 0.350546 0.420655 0.244332 0.637280 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1366.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1366.txt new file mode 100644 index 0000000..be7cdff --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1366.txt @@ -0,0 +1,2 @@ +0 0.834173 0.420025 0.249370 0.275819 +1 0.372586 0.499370 0.668766 0.434509 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1375.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1375.txt new file mode 100644 index 0000000..d36b4c4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1375.txt @@ -0,0 +1 @@ +1 0.497753 0.515743 0.926424 0.923174 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1395.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1395.txt new file mode 100644 index 0000000..ce543aa --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1395.txt @@ -0,0 +1,2 @@ +0 0.706339 0.549118 0.434509 0.299748 +1 0.496641 0.501259 0.856423 0.403023 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1404.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1404.txt new file mode 100644 index 0000000..89cf49d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1404.txt @@ -0,0 +1,2 @@ +0 0.651553 0.668136 0.267003 0.164987 +1 0.499790 0.614610 0.578086 0.345088 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1417.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1417.txt new file mode 100644 index 0000000..5843c23 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1417.txt @@ -0,0 +1 @@ +1 0.502939 0.520781 0.813602 0.235516 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1424.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1424.txt new file mode 100644 index 0000000..8a27144 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1424.txt @@ -0,0 +1,2 @@ +0 0.681150 0.575567 0.326196 0.317380 +1 0.349286 0.492443 0.335013 0.478589 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1433.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1433.txt new file mode 100644 index 0000000..f1c07dc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1433.txt @@ -0,0 +1,2 @@ +0 0.490344 0.667506 0.277078 0.418136 +1 0.500420 0.288413 0.508816 0.307305 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1443.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1443.txt new file mode 100644 index 0000000..12c6dbe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1443.txt @@ -0,0 +1,2 @@ +0 0.758606 0.387909 0.269521 0.345088 +1 0.369437 0.500000 0.528967 0.566751 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1457.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1457.txt new file mode 100644 index 0000000..8166169 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1457.txt @@ -0,0 +1 @@ +1 0.501321 0.496222 0.997358 0.992443 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1464.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1464.txt new file mode 100644 index 0000000..3ad2245 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1464.txt @@ -0,0 +1,2 @@ +0 0.434929 0.788413 0.755668 0.307305 +1 0.497271 0.348237 0.875315 0.578086 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1477.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1477.txt new file mode 100644 index 0000000..d1700c9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1477.txt @@ -0,0 +1,2 @@ +0 0.706420 0.789673 0.269487 0.176322 +1 0.709911 0.512594 0.270883 0.380353 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1484.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1484.txt new file mode 100644 index 0000000..618b377 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1484.txt @@ -0,0 +1 @@ +1 0.499790 0.517632 0.643577 0.574307 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1493.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1493.txt new file mode 100644 index 0000000..f16d648 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1493.txt @@ -0,0 +1,2 @@ +0 0.733417 0.386020 0.312343 0.301008 +1 0.330395 0.497481 0.465995 0.523929 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1506.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1506.txt new file mode 100644 index 0000000..0f970cf --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1506.txt @@ -0,0 +1 @@ +1 0.492863 0.505668 0.539043 0.817380 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1514.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1514.txt new file mode 100644 index 0000000..8b021b0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1514.txt @@ -0,0 +1 @@ +1 0.504828 0.483627 0.812343 0.178841 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1616.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1616.txt new file mode 100644 index 0000000..b6b8d70 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1616.txt @@ -0,0 +1 @@ +1 0.496728 0.554786 0.965787 0.875315 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1623.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1623.txt new file mode 100644 index 0000000..45729ad --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1623.txt @@ -0,0 +1 @@ +1 0.511484 0.390428 0.950857 0.768262 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1633.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1633.txt new file mode 100644 index 0000000..415f55f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1633.txt @@ -0,0 +1,2 @@ +0 0.447523 0.742443 0.539043 0.255668 +1 0.497901 0.368388 0.652393 0.484887 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1645.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1645.txt new file mode 100644 index 0000000..6952209 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1645.txt @@ -0,0 +1 @@ +1 0.518682 0.468514 0.575567 0.329975 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1656.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1656.txt new file mode 100644 index 0000000..ee1d81a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1656.txt @@ -0,0 +1,2 @@ +0 0.771872 0.369018 0.450378 0.700252 +1 0.273636 0.463476 0.538035 0.894207 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart166.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart166.txt new file mode 100644 index 0000000..5ca54d8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart166.txt @@ -0,0 +1 @@ +1 0.499835 0.494652 0.989130 0.975936 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1674.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1674.txt new file mode 100644 index 0000000..87b2fd0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1674.txt @@ -0,0 +1,2 @@ +0 0.288203 0.510705 0.313602 0.492443 +1 0.663518 0.501259 0.414358 0.511335 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1695.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1695.txt new file mode 100644 index 0000000..de3923b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1695.txt @@ -0,0 +1,2 @@ +0 0.706969 0.607053 0.382872 0.387909 +1 0.310243 0.668136 0.415617 0.431990 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1705.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1705.txt new file mode 100644 index 0000000..8fe1ece --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1705.txt @@ -0,0 +1 @@ +1 0.501340 0.500000 0.997320 1.000000 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1724.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1724.txt new file mode 100644 index 0000000..4b29227 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1724.txt @@ -0,0 +1 @@ +1 0.499790 0.519521 0.585642 0.401763 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1733.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1733.txt new file mode 100644 index 0000000..da5fb2e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1733.txt @@ -0,0 +1,2 @@ +0 0.471453 0.810453 0.211587 0.243073 +1 0.497901 0.375315 0.261965 0.634761 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1764.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1764.txt new file mode 100644 index 0000000..2fc4af9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1764.txt @@ -0,0 +1 @@ +1 0.496581 0.435139 0.916890 0.829975 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1774.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1774.txt new file mode 100644 index 0000000..0827bc2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1774.txt @@ -0,0 +1,2 @@ +0 0.211377 0.465995 0.298489 0.153652 +1 0.652813 0.497481 0.594458 0.211587 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1784.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1784.txt new file mode 100644 index 0000000..fdaac88 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1784.txt @@ -0,0 +1,2 @@ +0 0.497271 0.644836 0.253149 0.622166 +1 0.518052 0.183249 0.695214 0.250630 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1804.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1804.txt new file mode 100644 index 0000000..711a8ff --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1804.txt @@ -0,0 +1 @@ +1 0.514274 0.512594 0.609572 0.438287 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1816.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1816.txt new file mode 100644 index 0000000..c268916 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1816.txt @@ -0,0 +1 @@ +1 0.485936 0.516373 0.900504 0.788413 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1833.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1833.txt new file mode 100644 index 0000000..30a1426 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1833.txt @@ -0,0 +1,2 @@ +0 0.497271 0.765743 0.772040 0.214106 +1 0.496641 0.387909 0.773300 0.526448 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1856.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1856.txt new file mode 100644 index 0000000..a65cec7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1856.txt @@ -0,0 +1 @@ +1 0.499341 0.506324 0.990119 0.986561 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1893.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1893.txt new file mode 100644 index 0000000..a60d7ce --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1893.txt @@ -0,0 +1 @@ +1 0.496641 0.503149 0.566751 0.787154 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1905.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1905.txt new file mode 100644 index 0000000..2efc138 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1905.txt @@ -0,0 +1 @@ +0 0.498847 0.497651 0.993083 0.958591 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1913.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1913.txt new file mode 100644 index 0000000..3f0eeef --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1913.txt @@ -0,0 +1 @@ +1 0.499790 0.499370 0.792191 0.394207 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1924.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1924.txt new file mode 100644 index 0000000..c979388 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart1924.txt @@ -0,0 +1 @@ +1 0.500329 0.498419 0.990119 0.973913 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2016.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2016.txt new file mode 100644 index 0000000..a082663 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2016.txt @@ -0,0 +1 @@ +1 0.497365 0.494466 0.994071 0.988142 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2035.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2035.txt new file mode 100644 index 0000000..3614c41 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2035.txt @@ -0,0 +1 @@ +1 0.509866 0.482368 0.971033 0.700252 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2056.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2056.txt new file mode 100644 index 0000000..5d24c41 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2056.txt @@ -0,0 +1 @@ +1 0.495382 0.505668 0.889169 0.625945 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2065.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2065.txt new file mode 100644 index 0000000..a6536c6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2065.txt @@ -0,0 +1,2 @@ +0 0.500420 0.620277 0.670025 0.515113 +1 0.499160 0.234887 0.702771 0.253149 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2106.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2106.txt new file mode 100644 index 0000000..ed5afa3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2106.txt @@ -0,0 +1 @@ +1 0.489714 0.503149 0.900504 0.462217 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2116.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2116.txt new file mode 100644 index 0000000..432a70b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2116.txt @@ -0,0 +1 @@ +1 0.497365 0.379722 0.962451 0.692510 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2126.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2126.txt new file mode 100644 index 0000000..35fd957 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2126.txt @@ -0,0 +1 @@ +1 0.480269 0.481738 0.876574 0.356423 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2134.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2134.txt new file mode 100644 index 0000000..bd7e557 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2134.txt @@ -0,0 +1 @@ +1 0.500420 0.497481 0.594458 0.395466 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2143.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2143.txt new file mode 100644 index 0000000..a310925 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2143.txt @@ -0,0 +1 @@ +1 0.502309 0.500000 0.817380 0.342569 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2164.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2164.txt new file mode 100644 index 0000000..f7d3994 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2164.txt @@ -0,0 +1,2 @@ +0 0.796390 0.497481 0.138539 0.539043 +1 0.431150 0.465995 0.586902 0.486146 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2184.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2184.txt new file mode 100644 index 0000000..14055f0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2184.txt @@ -0,0 +1 @@ +1 0.502309 0.500630 0.701511 0.318640 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2196.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2196.txt new file mode 100644 index 0000000..11f3972 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2196.txt @@ -0,0 +1 @@ +1 0.500329 0.365953 0.960474 0.731906 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2224.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2224.txt new file mode 100644 index 0000000..8805223 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2224.txt @@ -0,0 +1 @@ +1 0.500420 0.499370 0.926952 0.248111 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2236.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2236.txt new file mode 100644 index 0000000..c8930fd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2236.txt @@ -0,0 +1 @@ +1 0.497859 0.494358 0.989130 0.981661 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2254.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2254.txt new file mode 100644 index 0000000..5bab2be --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2254.txt @@ -0,0 +1,2 @@ +0 0.748531 0.522040 0.249370 0.248111 +1 0.375105 0.524559 0.507557 0.265743 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2274.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2274.txt new file mode 100644 index 0000000..0ddb365 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2274.txt @@ -0,0 +1 @@ +1 0.494123 0.486146 0.624685 0.249370 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2286.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2286.txt new file mode 100644 index 0000000..f893df3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2286.txt @@ -0,0 +1 @@ +1 0.503568 0.498111 0.930730 0.406801 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2294.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2294.txt new file mode 100644 index 0000000..6b1296d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2294.txt @@ -0,0 +1 @@ +1 0.502309 0.510705 0.598237 0.273300 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2314.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2314.txt new file mode 100644 index 0000000..f62bb7e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2314.txt @@ -0,0 +1,2 @@ +0 0.497271 0.732997 0.754408 0.168766 +1 0.499160 0.410579 0.743073 0.455919 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart233.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart233.txt new file mode 100644 index 0000000..7584d74 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart233.txt @@ -0,0 +1 @@ +1 0.489714 0.505668 0.615869 0.437028 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2334.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2334.txt new file mode 100644 index 0000000..66b69eb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2334.txt @@ -0,0 +1,2 @@ +0 0.500420 0.745592 0.785894 0.506297 +1 0.501050 0.245592 0.993703 0.483627 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2344.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2344.txt new file mode 100644 index 0000000..fac3e5c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2344.txt @@ -0,0 +1,2 @@ +0 0.349286 0.659320 0.448363 0.182620 +1 0.505458 0.410579 0.750630 0.319899 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2364.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2364.txt new file mode 100644 index 0000000..b06ab5b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2364.txt @@ -0,0 +1 @@ +1 0.499790 0.518262 0.784635 0.464736 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2396.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2396.txt new file mode 100644 index 0000000..ab0b210 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2396.txt @@ -0,0 +1 @@ +1 0.499835 0.498419 0.997036 0.992885 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart24.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart24.txt new file mode 100644 index 0000000..167bd69 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart24.txt @@ -0,0 +1 @@ +1 0.475861 0.503149 0.666247 0.497481 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2414.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2414.txt new file mode 100644 index 0000000..f2c536b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2414.txt @@ -0,0 +1,2 @@ +0 0.387699 0.751259 0.479849 0.170025 +1 0.500420 0.413098 0.695214 0.503778 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2423.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2423.txt new file mode 100644 index 0000000..ecaa3f8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2423.txt @@ -0,0 +1,2 @@ +0 0.740344 0.728589 0.389169 0.497481 +1 0.490344 0.501259 0.896725 0.952141 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2434.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2434.txt new file mode 100644 index 0000000..40dbedd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2434.txt @@ -0,0 +1,2 @@ +0 0.395256 0.797229 0.278338 0.065491 +1 0.493493 0.680730 0.479849 0.162469 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart244.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart244.txt new file mode 100644 index 0000000..32dacb0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart244.txt @@ -0,0 +1 @@ +1 0.501679 0.501889 0.619647 0.426952 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2443.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2443.txt new file mode 100644 index 0000000..58235a6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2443.txt @@ -0,0 +1,2 @@ +0 0.657851 0.620907 0.476071 0.166247 +1 0.506717 0.481108 0.788413 0.450882 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2504.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2504.txt new file mode 100644 index 0000000..ad14033 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2504.txt @@ -0,0 +1,2 @@ +0 0.365029 0.782116 0.358942 0.080605 +1 0.489085 0.637280 0.604534 0.211587 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2513.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2513.txt new file mode 100644 index 0000000..e8bdbcd --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2513.txt @@ -0,0 +1,2 @@ +0 0.725231 0.664358 0.351385 0.449622 +1 0.310873 0.499370 0.406801 0.789673 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2524.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2524.txt new file mode 100644 index 0000000..1034f9a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2524.txt @@ -0,0 +1,2 @@ +0 0.501050 0.646096 0.744332 0.125945 +1 0.500420 0.423174 0.750630 0.274559 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart253.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart253.txt new file mode 100644 index 0000000..cafd170 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart253.txt @@ -0,0 +1 @@ +1 0.505458 0.494962 0.559194 0.657431 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2533.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2533.txt new file mode 100644 index 0000000..0e88bae --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2533.txt @@ -0,0 +1,2 @@ +0 0.680521 0.602015 0.385390 0.244332 +1 0.311503 0.494962 0.342569 0.473552 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2553.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2553.txt new file mode 100644 index 0000000..a53f207 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2553.txt @@ -0,0 +1,2 @@ +0 0.501050 0.396096 0.993703 0.159950 +1 0.501469 0.496851 0.997061 0.802267 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2564.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2564.txt new file mode 100644 index 0000000..de74281 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2564.txt @@ -0,0 +1,2 @@ +0 0.500420 0.840680 0.463476 0.122166 +1 0.497271 0.452771 0.482368 0.653652 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2573.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2573.txt new file mode 100644 index 0000000..6a413a3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2573.txt @@ -0,0 +1,2 @@ +0 0.498531 0.811083 0.389169 0.176322 +1 0.496641 0.416877 0.342569 0.604534 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2584.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2584.txt new file mode 100644 index 0000000..26a60a0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2584.txt @@ -0,0 +1,2 @@ +0 0.504198 0.765743 0.581864 0.173804 +1 0.501679 0.411209 0.602015 0.550378 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2594.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2594.txt new file mode 100644 index 0000000..9219291 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2594.txt @@ -0,0 +1,2 @@ +0 0.701301 0.621537 0.401763 0.439547 +1 0.283165 0.498111 0.358942 0.676322 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2604.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2604.txt new file mode 100644 index 0000000..426e8f6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2604.txt @@ -0,0 +1,2 @@ +0 0.486566 0.430730 0.813602 0.244332 +1 0.480269 0.654912 0.836272 0.136020 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2614.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2614.txt new file mode 100644 index 0000000..06cc7f1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2614.txt @@ -0,0 +1,2 @@ +0 0.735306 0.280856 0.411839 0.528967 +1 0.497271 0.501259 0.903023 0.964736 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2624.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2624.txt new file mode 100644 index 0000000..17796b6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2624.txt @@ -0,0 +1,2 @@ +0 0.712007 0.598237 0.445844 0.156171 +1 0.276238 0.506297 0.445844 0.596977 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2634.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2634.txt new file mode 100644 index 0000000..ad8a406 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2634.txt @@ -0,0 +1,2 @@ +0 0.671704 0.632242 0.345088 0.335013 +1 0.317800 0.498741 0.324937 0.622166 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart264.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart264.txt new file mode 100644 index 0000000..1e62221 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart264.txt @@ -0,0 +1,2 @@ +0 0.243493 0.632872 0.428212 0.132242 +1 0.503568 0.433249 0.933249 0.269521 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2646.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2646.txt new file mode 100644 index 0000000..d44b7eb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2646.txt @@ -0,0 +1,2 @@ +0 0.761693 0.258386 0.455534 0.469616 +1 0.501318 0.496597 0.986166 0.986874 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2653.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2653.txt new file mode 100644 index 0000000..2e848d9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2653.txt @@ -0,0 +1,2 @@ +0 0.504198 0.761965 0.521411 0.171285 +1 0.504198 0.412469 0.551637 0.532746 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2663.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2663.txt new file mode 100644 index 0000000..a198e6f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2663.txt @@ -0,0 +1,2 @@ +0 0.757976 0.750000 0.384131 0.489924 +1 0.498531 0.505038 0.918136 0.989924 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2673.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2673.txt new file mode 100644 index 0000000..8a29e7a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2673.txt @@ -0,0 +1,2 @@ +0 0.494752 0.696474 0.620907 0.216625 +1 0.495382 0.352645 0.614610 0.481108 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2684.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2684.txt new file mode 100644 index 0000000..5a3e71f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2684.txt @@ -0,0 +1,2 @@ +0 0.830316 0.396725 0.337674 0.569270 +1 0.336109 0.498741 0.672218 0.768262 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2703.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2703.txt new file mode 100644 index 0000000..c777b2e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2703.txt @@ -0,0 +1,2 @@ +0 0.496012 0.566121 0.709068 0.217884 +1 0.501050 0.389169 0.751889 0.128463 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2714.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2714.txt new file mode 100644 index 0000000..a2133d5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2714.txt @@ -0,0 +1,2 @@ +0 0.500420 0.739924 0.448363 0.426952 +1 0.503359 0.278967 0.993282 0.459698 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart273.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart273.txt new file mode 100644 index 0000000..230873d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart273.txt @@ -0,0 +1 @@ +1 0.484047 0.498741 0.471033 0.559194 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2734.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2734.txt new file mode 100644 index 0000000..ca0e3b8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2734.txt @@ -0,0 +1,2 @@ +0 0.485936 0.772040 0.371537 0.191436 +1 0.486566 0.386650 0.367758 0.486146 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2794.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2794.txt new file mode 100644 index 0000000..66843b2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2794.txt @@ -0,0 +1,2 @@ +0 0.493493 0.680730 0.719144 0.235516 +1 0.496012 0.383501 0.744332 0.306045 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2806.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2806.txt new file mode 100644 index 0000000..865adfe --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2806.txt @@ -0,0 +1,2 @@ +0 0.666667 0.228589 0.438287 0.306045 +1 0.499160 0.650504 0.768262 0.535264 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2814.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2814.txt new file mode 100644 index 0000000..2936224 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2814.txt @@ -0,0 +1,2 @@ +0 0.523615 0.198992 0.341555 0.327456 +1 0.519887 0.614610 0.343046 0.511335 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2824.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2824.txt new file mode 100644 index 0000000..16a16cb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2824.txt @@ -0,0 +1,2 @@ +0 0.499749 0.816751 0.904792 0.273300 +1 0.492974 0.340680 0.909308 0.439547 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2835.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2835.txt new file mode 100644 index 0000000..13b57e5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2835.txt @@ -0,0 +1,2 @@ +0 0.360216 0.842569 0.669022 0.282116 +1 0.487476 0.360202 0.938086 0.680101 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart284.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart284.txt new file mode 100644 index 0000000..a2edabc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart284.txt @@ -0,0 +1 @@ +1 0.492863 0.504408 0.795970 0.683879 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2843.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2843.txt new file mode 100644 index 0000000..0a428a8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2843.txt @@ -0,0 +1,2 @@ +0 0.785055 0.705919 0.340050 0.472292 +1 0.497271 0.488665 0.920655 0.924433 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2854.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2854.txt new file mode 100644 index 0000000..8aac241 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2854.txt @@ -0,0 +1,2 @@ +0 0.260705 0.409251 0.265810 0.716437 +1 0.681159 0.496179 0.555336 0.886472 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2864.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2864.txt new file mode 100644 index 0000000..9e591d5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2864.txt @@ -0,0 +1,2 @@ +0 0.785902 0.501949 0.416996 0.947257 +1 0.291831 0.500000 0.567194 0.951155 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2874.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2874.txt new file mode 100644 index 0000000..c88293f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2874.txt @@ -0,0 +1,2 @@ +0 0.500612 0.790302 0.727662 0.137280 +1 0.494181 0.495592 0.744200 0.406801 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2884.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2884.txt new file mode 100644 index 0000000..c39c3d6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2884.txt @@ -0,0 +1,2 @@ +0 0.434019 0.748111 0.863055 0.299748 +1 0.500914 0.299118 0.988072 0.585642 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2905.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2905.txt new file mode 100644 index 0000000..47fe894 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2905.txt @@ -0,0 +1,2 @@ +0 0.728590 0.711320 0.476285 0.444475 +1 0.497365 0.494542 0.950593 0.899866 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2914.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2914.txt new file mode 100644 index 0000000..acda477 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2914.txt @@ -0,0 +1,2 @@ +0 0.751050 0.563602 0.425693 0.283375 +1 0.281906 0.545340 0.454660 0.599496 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2924.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2924.txt new file mode 100644 index 0000000..6315de6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2924.txt @@ -0,0 +1,2 @@ +0 0.754198 0.520151 0.265743 0.347607 +1 0.363770 0.498741 0.500000 0.400504 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2933.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2933.txt new file mode 100644 index 0000000..1c9eecf --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2933.txt @@ -0,0 +1,2 @@ +0 0.652183 0.270151 0.288413 0.217884 +1 0.499790 0.499370 0.663728 0.704030 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart294.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart294.txt new file mode 100644 index 0000000..1107ee2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart294.txt @@ -0,0 +1 @@ +1 0.492233 0.477960 0.734257 0.862720 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2943.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2943.txt new file mode 100644 index 0000000..4da4f9a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2943.txt @@ -0,0 +1,2 @@ +0 0.723971 0.430730 0.265743 0.642317 +1 0.504198 0.500630 0.710327 0.792191 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2954.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2954.txt new file mode 100644 index 0000000..1e62f67 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2954.txt @@ -0,0 +1,2 @@ +0 0.735936 0.505038 0.274559 0.377834 +1 0.368808 0.506297 0.414358 0.370277 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2973.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2973.txt new file mode 100644 index 0000000..561de55 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2973.txt @@ -0,0 +1,2 @@ +0 0.066041 0.504509 0.083992 0.934790 +1 0.502800 0.496994 0.196640 0.949819 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2993.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2993.txt new file mode 100644 index 0000000..6dbb521 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart2993.txt @@ -0,0 +1,2 @@ +0 0.316541 0.669395 0.410579 0.316121 +1 0.712007 0.492443 0.372796 0.672544 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3014.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3014.txt new file mode 100644 index 0000000..c0c741f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3014.txt @@ -0,0 +1 @@ +1 0.493493 0.509446 0.774559 0.343829 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3023.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3023.txt new file mode 100644 index 0000000..829c984 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3023.txt @@ -0,0 +1,2 @@ +0 0.749341 0.514705 0.422925 0.290429 +1 0.499835 0.378682 0.979249 0.727910 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3034.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3034.txt new file mode 100644 index 0000000..e907328 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3034.txt @@ -0,0 +1 @@ +1 0.494895 0.464933 0.947628 0.746923 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart304.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart304.txt new file mode 100644 index 0000000..71bc2f9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart304.txt @@ -0,0 +1 @@ +1 0.513014 0.496851 0.594458 0.829975 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3044.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3044.txt new file mode 100644 index 0000000..eade227 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3044.txt @@ -0,0 +1,2 @@ +0 0.507347 0.661209 0.333753 0.503778 +1 0.507976 0.245592 0.614610 0.226700 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3053.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3053.txt new file mode 100644 index 0000000..d806f3a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3053.txt @@ -0,0 +1,2 @@ +0 0.491604 0.756297 0.463476 0.175063 +1 0.489714 0.396725 0.464736 0.491184 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3066.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3066.txt new file mode 100644 index 0000000..6aa4c53 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3066.txt @@ -0,0 +1,2 @@ +0 0.733513 0.618388 0.466195 0.471033 +1 0.491690 0.440176 0.952333 0.862720 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3075.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3075.txt new file mode 100644 index 0000000..3b1267c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3075.txt @@ -0,0 +1,2 @@ +0 0.503755 0.852645 0.979936 0.267003 +1 0.501502 0.364610 0.979936 0.716625 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3084.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3084.txt new file mode 100644 index 0000000..3c4b754 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3084.txt @@ -0,0 +1 @@ +1 0.496012 0.486146 0.615869 0.843829 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3094.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3094.txt new file mode 100644 index 0000000..6033143 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3094.txt @@ -0,0 +1,2 @@ +0 0.687447 0.526448 0.583123 0.254408 +1 0.208228 0.545340 0.317380 0.659950 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart314.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart314.txt new file mode 100644 index 0000000..8a4168c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart314.txt @@ -0,0 +1,2 @@ +0 0.499790 0.730479 0.306045 0.329975 +1 0.499160 0.333753 0.309824 0.468514 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3154.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3154.txt new file mode 100644 index 0000000..4d7c3a8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3154.txt @@ -0,0 +1 @@ +1 0.499676 0.650504 0.888594 0.598237 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3163.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3163.txt new file mode 100644 index 0000000..359c56b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3163.txt @@ -0,0 +1,2 @@ +0 0.443919 0.727960 0.277407 0.511335 +1 0.508767 0.531486 0.982465 0.899244 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3174.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3174.txt new file mode 100644 index 0000000..7d6df4d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3174.txt @@ -0,0 +1,2 @@ +0 0.739085 0.345718 0.333753 0.190176 +1 0.492233 0.467884 0.829975 0.442065 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3185.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3185.txt new file mode 100644 index 0000000..669edc6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3185.txt @@ -0,0 +1,2 @@ +0 0.683959 0.800061 0.632082 0.389690 +1 0.684947 0.300660 0.630105 0.601319 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3203.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3203.txt new file mode 100644 index 0000000..c7ef288 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3203.txt @@ -0,0 +1,2 @@ +0 0.499790 0.535264 0.439547 0.302267 +1 0.499160 0.498741 0.435768 0.722922 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3214.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3214.txt new file mode 100644 index 0000000..c39634d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3214.txt @@ -0,0 +1,2 @@ +0 0.487430 0.688287 0.931648 0.195214 +1 0.488539 0.294710 0.929429 0.586902 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3226.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3226.txt new file mode 100644 index 0000000..d29d797 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3226.txt @@ -0,0 +1,2 @@ +0 0.756258 0.521909 0.432806 0.310542 +1 0.501318 0.397121 0.974308 0.762067 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3234.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3234.txt new file mode 100644 index 0000000..9811a1b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3234.txt @@ -0,0 +1 @@ +1 0.734801 0.496222 0.491378 0.984887 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart324.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart324.txt new file mode 100644 index 0000000..127fd72 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart324.txt @@ -0,0 +1,2 @@ +0 0.770833 0.642947 0.442983 0.568010 +1 0.272341 0.496222 0.540940 0.989924 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3244.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3244.txt new file mode 100644 index 0000000..c2d8849 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3244.txt @@ -0,0 +1,2 @@ +0 0.822892 0.274559 0.328256 0.511335 +1 0.332439 0.345718 0.652650 0.646096 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3254.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3254.txt new file mode 100644 index 0000000..b49bc66 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3254.txt @@ -0,0 +1 @@ +1 0.499088 0.535894 0.965590 0.469773 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3263.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3263.txt new file mode 100644 index 0000000..3fa5d89 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3263.txt @@ -0,0 +1,2 @@ +0 0.501679 0.721662 0.551637 0.236776 +1 0.503568 0.384761 0.560453 0.447103 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3273.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3273.txt new file mode 100644 index 0000000..e1d1527 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3273.txt @@ -0,0 +1,2 @@ +0 0.501296 0.744962 0.902302 0.238035 +1 0.501296 0.356423 0.902302 0.534005 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3284.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3284.txt new file mode 100644 index 0000000..12c27a6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3284.txt @@ -0,0 +1 @@ +1 0.500533 0.401763 0.950513 0.785894 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3294.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3294.txt new file mode 100644 index 0000000..c177c46 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3294.txt @@ -0,0 +1,2 @@ +0 0.632032 0.640428 0.270781 0.479849 +1 0.351805 0.501259 0.241814 0.763224 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart33.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart33.txt new file mode 100644 index 0000000..53a66bf --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart33.txt @@ -0,0 +1 @@ +1 0.510495 0.484257 0.659950 0.442065 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3306.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3306.txt new file mode 100644 index 0000000..7baf08b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3306.txt @@ -0,0 +1,2 @@ +0 0.786944 0.405542 0.321159 0.445844 +1 0.331654 0.501889 0.574307 0.648615 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3314.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3314.txt new file mode 100644 index 0000000..b43739c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3314.txt @@ -0,0 +1,2 @@ +0 0.353065 0.848237 0.503778 0.238035 +1 0.499790 0.496851 0.797229 0.462217 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3326.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3326.txt new file mode 100644 index 0000000..318abfc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3326.txt @@ -0,0 +1,2 @@ +0 0.391044 0.755668 0.550420 0.143577 +1 0.500594 0.407431 0.776645 0.555416 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3334.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3334.txt new file mode 100644 index 0000000..14c70d8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3334.txt @@ -0,0 +1 @@ +1 0.501050 0.501889 0.935768 0.132242 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart335.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart335.txt new file mode 100644 index 0000000..e0195ac --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart335.txt @@ -0,0 +1,2 @@ +0 0.489085 0.673174 0.622166 0.379093 +1 0.491604 0.319899 0.823678 0.269521 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3393.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3393.txt new file mode 100644 index 0000000..6dc5d8c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3393.txt @@ -0,0 +1,2 @@ +0 0.380772 0.788413 0.420655 0.148615 +1 0.501050 0.431990 0.646096 0.589421 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3403.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3403.txt new file mode 100644 index 0000000..c29ab4f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3403.txt @@ -0,0 +1 @@ +1 0.500000 0.500000 1.000000 1.000000 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3415.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3415.txt new file mode 100644 index 0000000..c7454b3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3415.txt @@ -0,0 +1 @@ +1 0.488455 0.492443 0.897985 0.602015 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3424.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3424.txt new file mode 100644 index 0000000..8943cdc --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3424.txt @@ -0,0 +1,2 @@ +0 0.460747 0.806675 0.333753 0.102015 +1 0.499790 0.444584 0.434509 0.609572 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3433.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3433.txt new file mode 100644 index 0000000..867db56 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3433.txt @@ -0,0 +1 @@ +1 0.499160 0.497481 0.607053 0.750630 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3443.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3443.txt new file mode 100644 index 0000000..4f82043 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3443.txt @@ -0,0 +1,2 @@ +0 0.410369 0.748741 0.459698 0.159950 +1 0.501679 0.403023 0.632242 0.531486 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3453.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3453.txt new file mode 100644 index 0000000..c29ab4f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3453.txt @@ -0,0 +1 @@ +1 0.500000 0.500000 1.000000 1.000000 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3465.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3465.txt new file mode 100644 index 0000000..a6855be --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3465.txt @@ -0,0 +1 @@ +1 0.501866 0.479219 0.943313 0.923174 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3476.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3476.txt new file mode 100644 index 0000000..07ee60f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3476.txt @@ -0,0 +1 @@ +1 0.486566 0.506927 0.788413 0.837531 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3484.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3484.txt new file mode 100644 index 0000000..31381d8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3484.txt @@ -0,0 +1,2 @@ +1 0.501679 0.501259 0.571788 0.700252 +0 0.439337 0.646096 0.437028 0.163728 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3496.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3496.txt new file mode 100644 index 0000000..6bc4225 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3496.txt @@ -0,0 +1 @@ +1 0.507347 0.460957 0.895466 0.511335 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3504.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3504.txt new file mode 100644 index 0000000..8835e39 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3504.txt @@ -0,0 +1,2 @@ +0 0.514274 0.783375 0.269521 0.239295 +1 0.514903 0.377834 0.275819 0.564232 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart35110.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart35110.txt new file mode 100644 index 0000000..1b8edc9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart35110.txt @@ -0,0 +1 @@ +1 0.495382 0.429471 0.858942 0.483627 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3526.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3526.txt new file mode 100644 index 0000000..5fcf920 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3526.txt @@ -0,0 +1 @@ +1 0.489714 0.482368 0.842569 0.531486 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3535.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3535.txt new file mode 100644 index 0000000..13c7560 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3535.txt @@ -0,0 +1 @@ +1 0.491691 0.501889 0.973560 0.996222 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3543.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3543.txt new file mode 100644 index 0000000..ddc1e22 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3543.txt @@ -0,0 +1,2 @@ +0 0.800725 0.502372 0.387352 0.981818 +1 0.302701 0.498419 0.600791 0.977075 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3553.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3553.txt new file mode 100644 index 0000000..6d452f2 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3553.txt @@ -0,0 +1,2 @@ +0 0.816535 0.344553 0.363636 0.665248 +1 0.322958 0.500000 0.619565 0.976143 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3563.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3563.txt new file mode 100644 index 0000000..368abc3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3563.txt @@ -0,0 +1 @@ +1 0.497271 0.500630 0.935768 0.142317 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3575.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3575.txt new file mode 100644 index 0000000..32d4961 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3575.txt @@ -0,0 +1 @@ +1 0.509866 0.511965 0.787154 0.925693 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3586.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3586.txt new file mode 100644 index 0000000..666ffc6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3586.txt @@ -0,0 +1 @@ +1 0.501036 0.508186 0.824069 0.787154 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3596.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3596.txt new file mode 100644 index 0000000..a8ae022 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3596.txt @@ -0,0 +1,2 @@ +0 0.382662 0.777708 0.406801 0.132242 +1 0.491604 0.428841 0.622166 0.568010 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3607.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3607.txt new file mode 100644 index 0000000..a772803 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3607.txt @@ -0,0 +1,4 @@ +0 0.717044 0.149874 0.226700 0.267003 +0 0.715785 0.687028 0.224181 0.283375 +1 0.503568 0.280227 0.663728 0.527708 +1 0.499160 0.767632 0.657431 0.444584 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3614.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3614.txt new file mode 100644 index 0000000..f2bc4b1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3614.txt @@ -0,0 +1 @@ +1 0.498531 0.500000 0.706549 0.272040 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3624.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3624.txt new file mode 100644 index 0000000..b6373e9 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3624.txt @@ -0,0 +1 @@ +1 0.499790 0.498741 0.693955 0.541562 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3634.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3634.txt new file mode 100644 index 0000000..64165c7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3634.txt @@ -0,0 +1 @@ +1 0.479639 0.512594 0.767003 0.649874 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3644.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3644.txt new file mode 100644 index 0000000..9e2c2b8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3644.txt @@ -0,0 +1 @@ +1 0.501050 0.490554 0.749370 0.827456 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3654.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3654.txt new file mode 100644 index 0000000..460247e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3654.txt @@ -0,0 +1 @@ +1 0.503568 0.508816 0.726700 0.516373 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3665.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3665.txt new file mode 100644 index 0000000..7eff059 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3665.txt @@ -0,0 +1 @@ +1 0.499160 0.480479 0.798489 0.807305 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3674.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3674.txt new file mode 100644 index 0000000..dc29720 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3674.txt @@ -0,0 +1,2 @@ +0 0.696264 0.562972 0.389169 0.161209 +1 0.501050 0.501259 0.809824 0.299748 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3694.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3694.txt new file mode 100644 index 0000000..8831186 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3694.txt @@ -0,0 +1 @@ +1 0.504198 0.469144 0.720403 0.840050 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3713.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3713.txt new file mode 100644 index 0000000..841456c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3713.txt @@ -0,0 +1 @@ +1 0.500420 0.501259 0.750630 0.390428 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3724.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3724.txt new file mode 100644 index 0000000..2b1a337 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3724.txt @@ -0,0 +1 @@ +1 0.492863 0.532116 0.554156 0.253149 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3734.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3734.txt new file mode 100644 index 0000000..108a05b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3734.txt @@ -0,0 +1 @@ +1 0.518682 0.488035 0.618388 0.555416 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3743.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3743.txt new file mode 100644 index 0000000..e47cc2b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3743.txt @@ -0,0 +1 @@ +1 0.512385 0.494962 0.862720 0.836272 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3754.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3754.txt new file mode 100644 index 0000000..52d98a5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3754.txt @@ -0,0 +1 @@ +1 0.488455 0.506297 0.641058 0.647355 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3763.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3763.txt new file mode 100644 index 0000000..d61f7ef --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3763.txt @@ -0,0 +1 @@ +1 0.496641 0.500000 0.768262 0.760705 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3774.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3774.txt new file mode 100644 index 0000000..d79259d --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3774.txt @@ -0,0 +1 @@ +1 0.504828 0.503778 0.817380 0.649874 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3783.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3783.txt new file mode 100644 index 0000000..4e16fb7 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3783.txt @@ -0,0 +1 @@ +1 0.494123 0.496851 0.826196 0.731738 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3794.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3794.txt new file mode 100644 index 0000000..b1fe619 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3794.txt @@ -0,0 +1,2 @@ +0 0.436188 0.658060 0.536524 0.172544 +1 0.547649 0.396096 0.492443 0.288413 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3844.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3844.txt new file mode 100644 index 0000000..421224c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3844.txt @@ -0,0 +1 @@ +1 0.487196 0.499370 0.618388 0.434509 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3855.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3855.txt new file mode 100644 index 0000000..409ed87 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3855.txt @@ -0,0 +1,4 @@ +0 0.578505 0.444584 0.493703 0.176322 +0 0.451931 0.802897 0.416877 0.147355 +1 0.516793 0.327456 0.617128 0.415617 +1 0.530646 0.705290 0.584383 0.345088 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3863.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3863.txt new file mode 100644 index 0000000..dfcfff3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3863.txt @@ -0,0 +1 @@ +1 0.501153 0.501779 0.997694 0.996442 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3875.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3875.txt new file mode 100644 index 0000000..11a7602 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3875.txt @@ -0,0 +1 @@ +1 0.500165 0.827726 0.999670 0.338809 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3904.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3904.txt new file mode 100644 index 0000000..221080c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart3904.txt @@ -0,0 +1 @@ +1 0.497901 0.498111 0.619647 0.192695 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart404.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart404.txt new file mode 100644 index 0000000..744858c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart404.txt @@ -0,0 +1,2 @@ +0 0.725231 0.568010 0.245592 0.362720 +1 0.347397 0.510076 0.401763 0.478589 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart414.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart414.txt new file mode 100644 index 0000000..7d9c6e6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart414.txt @@ -0,0 +1,2 @@ +0 0.753091 0.692695 0.448238 0.609572 +1 0.227870 0.577456 0.445755 0.827456 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart426.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart426.txt new file mode 100644 index 0000000..216cd18 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart426.txt @@ -0,0 +1,2 @@ +0 0.234459 0.446474 0.351267 0.487406 +1 0.681697 0.496222 0.390158 0.828715 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart43.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart43.txt new file mode 100644 index 0000000..cec1699 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart43.txt @@ -0,0 +1 @@ +1 0.502309 0.317380 0.754408 0.284635 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart433.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart433.txt new file mode 100644 index 0000000..9a9a158 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart433.txt @@ -0,0 +1,2 @@ +0 0.706339 0.429471 0.343829 0.370277 +1 0.315911 0.475441 0.409320 0.462217 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart443.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart443.txt new file mode 100644 index 0000000..74b2bd0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart443.txt @@ -0,0 +1,2 @@ +0 0.499160 0.771411 0.435768 0.260705 +1 0.495382 0.367758 0.367758 0.541562 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart453.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart453.txt new file mode 100644 index 0000000..fcfaf26 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart453.txt @@ -0,0 +1,2 @@ +0 0.316541 0.501259 0.319899 0.556675 +1 0.672334 0.528338 0.333753 0.507557 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart464.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart464.txt new file mode 100644 index 0000000..dc4435a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart464.txt @@ -0,0 +1,2 @@ +0 0.313392 0.574307 0.482368 0.158690 +1 0.493493 0.503778 0.852645 0.304786 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart474.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart474.txt new file mode 100644 index 0000000..fb7656a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart474.txt @@ -0,0 +1,2 @@ +0 0.808984 0.501889 0.299748 0.374055 +1 0.349286 0.499370 0.614610 0.386650 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart484.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart484.txt new file mode 100644 index 0000000..e75ce48 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart484.txt @@ -0,0 +1,2 @@ +0 0.639589 0.650504 0.610831 0.401763 +1 0.499160 0.292191 0.924433 0.284635 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart494.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart494.txt new file mode 100644 index 0000000..a604920 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart494.txt @@ -0,0 +1,2 @@ +0 0.769941 0.484257 0.209068 0.278338 +1 0.391478 0.483627 0.545340 0.274559 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart504.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart504.txt new file mode 100644 index 0000000..6aacb6b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart504.txt @@ -0,0 +1,2 @@ +0 0.782536 0.500630 0.403023 0.338791 +1 0.300798 0.504408 0.555416 0.336272 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart515.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart515.txt new file mode 100644 index 0000000..e58eac1 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart515.txt @@ -0,0 +1,2 @@ +0 0.689966 0.539043 0.318640 0.345088 +1 0.294500 0.491814 0.338791 0.688917 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart524.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart524.txt new file mode 100644 index 0000000..457c2d4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart524.txt @@ -0,0 +1,2 @@ +0 0.502939 0.576826 0.609572 0.198992 +1 0.499790 0.409320 0.615869 0.110831 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart544.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart544.txt new file mode 100644 index 0000000..378c24c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart544.txt @@ -0,0 +1,2 @@ +0 0.751050 0.450252 0.287154 0.172544 +1 0.352435 0.495592 0.500000 0.270781 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart554.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart554.txt new file mode 100644 index 0000000..5aeb993 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart554.txt @@ -0,0 +1,2 @@ +0 0.685558 0.685768 0.322418 0.356423 +1 0.342359 0.506297 0.353904 0.732997 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart564.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart564.txt new file mode 100644 index 0000000..e56bf56 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart564.txt @@ -0,0 +1,2 @@ +0 0.492863 0.676952 0.392947 0.575567 +1 0.491604 0.224181 0.914358 0.314861 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart574.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart574.txt new file mode 100644 index 0000000..d5ed87a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart574.txt @@ -0,0 +1,2 @@ +0 0.492863 0.719144 0.246851 0.307305 +1 0.487825 0.343199 0.269521 0.447103 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart583.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart583.txt new file mode 100644 index 0000000..0716999 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart583.txt @@ -0,0 +1,2 @@ +0 0.307095 0.682620 0.348866 0.299748 +1 0.674853 0.496222 0.376574 0.672544 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart594.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart594.txt new file mode 100644 index 0000000..927c9c3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart594.txt @@ -0,0 +1,2 @@ +0 0.679261 0.521411 0.287154 0.478589 +1 0.315281 0.511335 0.340050 0.546599 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart606.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart606.txt new file mode 100644 index 0000000..0347ad4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart606.txt @@ -0,0 +1,2 @@ +0 0.249696 0.471033 0.342835 0.445844 +1 0.681438 0.484887 0.385050 0.828715 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart613.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart613.txt new file mode 100644 index 0000000..d745356 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart613.txt @@ -0,0 +1,2 @@ +0 0.495382 0.770151 0.780856 0.210327 +1 0.497271 0.391688 0.767003 0.528967 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart636.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart636.txt new file mode 100644 index 0000000..425d58a --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart636.txt @@ -0,0 +1 @@ +1 0.501411 0.496222 0.946096 0.879093 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart64.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart64.txt new file mode 100644 index 0000000..66466e3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart64.txt @@ -0,0 +1,2 @@ +0 0.310873 0.651134 0.404282 0.130982 +1 0.502939 0.435139 0.780856 0.313602 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart644.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart644.txt new file mode 100644 index 0000000..81b93d6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart644.txt @@ -0,0 +1,2 @@ +0 0.495382 0.761335 0.675063 0.147355 +1 0.500420 0.412469 0.259446 0.510076 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart694.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart694.txt new file mode 100644 index 0000000..84308e4 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart694.txt @@ -0,0 +1,2 @@ +0 0.501050 0.759446 0.557935 0.214106 +1 0.501050 0.394207 0.555416 0.503778 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart704.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart704.txt new file mode 100644 index 0000000..dcb3c1b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart704.txt @@ -0,0 +1,2 @@ +0 0.494752 0.639169 0.482368 0.328715 +1 0.486566 0.329345 0.768262 0.283375 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart714.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart714.txt new file mode 100644 index 0000000..da48e4c --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart714.txt @@ -0,0 +1 @@ +1 0.504828 0.496222 0.447103 0.591940 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart724.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart724.txt new file mode 100644 index 0000000..9bcdedb --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart724.txt @@ -0,0 +1,2 @@ +0 0.428631 0.724181 0.450882 0.141058 +1 0.497901 0.439547 0.591940 0.425693 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart733.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart733.txt new file mode 100644 index 0000000..f921c05 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart733.txt @@ -0,0 +1 @@ +1 0.495382 0.437657 0.559194 0.648615 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart744.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart744.txt new file mode 100644 index 0000000..3c64cf6 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart744.txt @@ -0,0 +1,2 @@ +0 0.314022 0.694584 0.458438 0.232997 +1 0.416667 0.506927 0.673804 0.608312 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart753.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart753.txt new file mode 100644 index 0000000..f03ef4f --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart753.txt @@ -0,0 +1,2 @@ +0 0.732158 0.377834 0.335013 0.267003 +1 0.506087 0.503149 0.789673 0.515113 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart765.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart765.txt new file mode 100644 index 0000000..87a8118 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart765.txt @@ -0,0 +1,2 @@ +0 0.775609 0.471662 0.225441 0.343829 +1 0.393997 0.472292 0.537783 0.347607 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart774.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart774.txt new file mode 100644 index 0000000..5003085 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart774.txt @@ -0,0 +1,2 @@ +0 0.790600 0.482368 0.372934 0.564232 +1 0.498739 0.444584 0.956657 0.811083 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart785.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart785.txt new file mode 100644 index 0000000..2680459 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart785.txt @@ -0,0 +1,2 @@ +0 0.504828 0.786524 0.646096 0.238035 +1 0.505458 0.387909 0.659950 0.564232 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart794.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart794.txt new file mode 100644 index 0000000..4f78d5b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart794.txt @@ -0,0 +1,2 @@ +0 0.713896 0.359572 0.245592 0.381612 +1 0.385180 0.499370 0.444584 0.673804 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart805.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart805.txt new file mode 100644 index 0000000..cd3a2ed --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart805.txt @@ -0,0 +1,2 @@ +0 0.759866 0.355793 0.251889 0.358942 +1 0.380772 0.500000 0.501259 0.654912 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart815.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart815.txt new file mode 100644 index 0000000..6070fac --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart815.txt @@ -0,0 +1,2 @@ +0 0.359362 0.637280 0.360202 0.168766 +1 0.495382 0.376574 0.629723 0.287154 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart824.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart824.txt new file mode 100644 index 0000000..ad9cdb3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart824.txt @@ -0,0 +1,2 @@ +0 0.745382 0.608312 0.190176 0.317380 +1 0.505458 0.506297 0.680101 0.534005 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart834.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart834.txt new file mode 100644 index 0000000..41906f5 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart834.txt @@ -0,0 +1,2 @@ +0 0.496871 0.862091 0.991181 0.275818 +1 0.501564 0.360202 0.993058 0.712846 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart84.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart84.txt new file mode 100644 index 0000000..70bbd99 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart84.txt @@ -0,0 +1 @@ +1 0.501050 0.493073 0.837531 0.464736 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart845.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart845.txt new file mode 100644 index 0000000..940e81b --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart845.txt @@ -0,0 +1 @@ +1 0.496641 0.496851 0.783375 0.462217 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart854.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart854.txt new file mode 100644 index 0000000..4a6e584 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart854.txt @@ -0,0 +1 @@ +1 0.502939 0.513224 0.727960 0.290932 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart864.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart864.txt new file mode 100644 index 0000000..f7393ae --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart864.txt @@ -0,0 +1,2 @@ +0 0.365029 0.782746 0.371537 0.177582 +1 0.499160 0.410579 0.637280 0.579345 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart874.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart874.txt new file mode 100644 index 0000000..f6f61b8 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart874.txt @@ -0,0 +1 @@ +1 0.497271 0.495592 0.653652 0.494962 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart886.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart886.txt new file mode 100644 index 0000000..8f752de --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart886.txt @@ -0,0 +1 @@ +1 0.504828 0.513854 0.588161 0.735516 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart894.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart894.txt new file mode 100644 index 0000000..ba0f494 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart894.txt @@ -0,0 +1,2 @@ +0 0.498528 0.857053 0.924712 0.258186 +1 0.501051 0.367128 0.947420 0.734256 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart904.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart904.txt new file mode 100644 index 0000000..86d4fb3 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart904.txt @@ -0,0 +1,2 @@ +0 0.730898 0.462217 0.198992 0.176322 +1 0.402813 0.500000 0.462217 0.256927 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart915.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart915.txt new file mode 100644 index 0000000..25da7aa --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart915.txt @@ -0,0 +1,2 @@ +0 0.488455 0.818640 0.374055 0.148615 +1 0.491604 0.422544 0.367758 0.648615 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart924.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart924.txt new file mode 100644 index 0000000..cae5891 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart924.txt @@ -0,0 +1,2 @@ +0 0.711377 0.706549 0.313602 0.153652 +1 0.506087 0.507557 0.736776 0.559194 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart955.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart955.txt new file mode 100644 index 0000000..f18a1aa --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart955.txt @@ -0,0 +1,2 @@ +0 0.652813 0.442065 0.282116 0.317380 +1 0.349286 0.494962 0.302267 0.790932 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart96.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart96.txt new file mode 100644 index 0000000..4009186 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart96.txt @@ -0,0 +1,2 @@ +0 0.369401 0.824111 0.720356 0.332016 +1 0.499341 0.337154 0.988142 0.673518 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart975.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart975.txt new file mode 100644 index 0000000..a06269e --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart975.txt @@ -0,0 +1 @@ +1 0.388669 0.512154 0.721344 0.926416 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart984.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart984.txt new file mode 100644 index 0000000..ea89626 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart984.txt @@ -0,0 +1 @@ +1 0.515533 0.540302 0.740554 0.387909 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/YOLO/train/labels/emart994.txt b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart994.txt new file mode 100644 index 0000000..a35a0b0 --- /dev/null +++ b/models/nutrition_ingredients_information/data/YOLO/train/labels/emart994.txt @@ -0,0 +1 @@ +1 0.499835 0.498878 0.969368 0.921882 \ No newline at end of file diff --git a/models/nutrition_ingredients_information/data/preprocessed/.gitkeep b/models/nutrition_ingredients_information/data/preprocessed/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/nutrition_ingredients_information/environment.yml b/models/nutrition_ingredients_information/environment.yml new file mode 100644 index 0000000..23694a6 --- /dev/null +++ b/models/nutrition_ingredients_information/environment.yml @@ -0,0 +1,93 @@ +name: nutrition_ingredients_information +channels: + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=1_gnu + - ca-certificates=2024.12.31=h06a4308_0 + - ld_impl_linux-64=2.40=h12ee557_0 + - libffi=3.4.4=h6a678d5_1 + - libgcc-ng=11.2.0=h1234567_1 + - libgomp=11.2.0=h1234567_1 + - libstdcxx-ng=11.2.0=h1234567_1 + - ncurses=6.4=h6a678d5_0 + - openssl=3.0.15=h5eee18b_0 + - pip=25.0=py39h06a4308_0 + - python=3.9.21=he870216_1 + - readline=8.2=h5eee18b_0 + - setuptools=75.8.0=py39h06a4308_0 + - sqlite=3.45.3=h5eee18b_0 + - tk=8.6.14=h39e8969_0 + - wheel=0.45.1=py39h06a4308_0 + - xz=5.4.6=h5eee18b_1 + - zlib=1.2.13=h5eee18b_1 + - pip: + - annotated-types==0.7.0 + - anyio==4.8.0 + - certifi==2025.1.31 + - charset-normalizer==3.4.1 + - contourpy==1.3.0 + - cycler==0.12.1 + - distro==1.9.0 + - exceptiongroup==1.2.2 + - filelock==3.17.0 + - fonttools==4.56.0 + - fsspec==2025.2.0 + - h11==0.14.0 + - httpcore==1.0.7 + - httpx==0.28.1 + - idna==3.10 + - importlib-resources==6.5.2 + - jinja2==3.1.5 + - jiter==0.8.2 + - kiwisolver==1.4.7 + - levenshtein==0.26.1 + - markupsafe==3.0.2 + - matplotlib==3.9.4 + - mpmath==1.3.0 + - networkx==3.2.1 + - numpy==2.0.2 + - nvidia-cublas-cu12==12.4.5.8 + - nvidia-cuda-cupti-cu12==12.4.127 + - nvidia-cuda-nvrtc-cu12==12.4.127 + - nvidia-cuda-runtime-cu12==12.4.127 + - nvidia-cudnn-cu12==9.1.0.70 + - nvidia-cufft-cu12==11.2.1.3 + - nvidia-curand-cu12==10.3.5.147 + - nvidia-cusolver-cu12==11.6.1.9 + - nvidia-cusparse-cu12==12.3.1.170 + - nvidia-cusparselt-cu12==0.6.2 + - nvidia-nccl-cu12==2.21.5 + - nvidia-nvjitlink-cu12==12.4.127 + - nvidia-nvtx-cu12==12.4.127 + - openai==1.61.1 + - opencv-python==4.11.0.86 + - packaging==24.2 + - pandas==2.2.3 + - pillow==11.1.0 + - psutil==6.1.1 + - py-cpuinfo==9.0.0 + - pydantic==2.10.6 + - pydantic-core==2.27.2 + - pyparsing==3.2.1 + - python-dateutil==2.9.0.post0 + - pytz==2025.1 + - pyyaml==6.0.2 + - rapidfuzz==3.12.1 + - requests==2.32.3 + - scipy==1.13.1 + - seaborn==0.13.2 + - six==1.17.0 + - sniffio==1.3.1 + - sympy==1.13.1 + - torch==2.6.0 + - torchvision==0.21.0 + - tqdm==4.67.1 + - triton==3.2.0 + - typing-extensions==4.12.2 + - tzdata==2025.1 + - ultralytics==8.3.74 + - ultralytics-thop==2.0.14 + - urllib3==2.3.0 + - zipp==3.21.0 +prefix: /data/ephemeral/home/.condaenv/envs/nutrition_ingredients_information diff --git a/models/nutrition_ingredients_information/main.py b/models/nutrition_ingredients_information/main.py new file mode 100644 index 0000000..ede359e --- /dev/null +++ b/models/nutrition_ingredients_information/main.py @@ -0,0 +1,79 @@ +import argparse +import yaml +import os +import logging +import subprocess + +def setup_logger(): + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + +def run_script(script_path): + """์ฃผ์–ด์ง„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜""" + try: + logging.info(f"Running: {script_path}") + subprocess.run(["python", script_path], check=True) + except subprocess.CalledProcessError as e: + logging.error(f"Error while executing {script_path}: {e}") + exit(1) + +# ์‹คํ–‰ ์ˆœ์„œ ์ •์˜ +PIPELINE_ORDER = { + "preprocessing": ["01_data_selection_323.py", "02_data_selection_273.py"], + "YOLO": ["01_data_conversion.py", "02_YOLO.py"], + "OCR": ["01_OCR_text.py", "02_OCR_row_col_323.py", "03_OCR_row_col_273_50.py"], + "Rule-based": ["01_rule_based.py", "02_eval_nutrition.py"], + "HCX": ["01_HCX_dataset.py", "02_HCX_train.py", "03_HCX_inference.py", "04_post_processing.py", "05_eval_ingredient.py"] +} + +def run_pipeline(pipeline_name, config): + """ํ•ด๋‹น ํŒŒ์ดํ”„๋ผ์ธ์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰""" + logging.info(f"{pipeline_name.upper()} ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์‹œ์ž‘") + + base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "src", pipeline_name) + + for script in PIPELINE_ORDER[pipeline_name]: + script_path = os.path.join(base_dir, script) + if os.path.exists(script_path): + run_script(script_path) + else: + logging.warning(f"ํŒŒ์ผ ์—†์Œ: {script_path} (๊ฑด๋„ˆ๋œ€)") + + logging.info(f"{pipeline_name.upper()} ํŒŒ์ดํ”„๋ผ์ธ ์™„๋ฃŒ.") + +def main(): + setup_logger() + parser = argparse.ArgumentParser(description="ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ (๊ธฐ๋ณธ๊ฐ’: config/config.yaml)" + ) + parser.add_argument( + "--pipeline", + "-p", + choices=["preprocessing", "YOLO", "OCR", "Rule-based", "HCX", "all"], + default="all", + help="์‹คํ–‰ํ•  ํŒŒ์ดํ”„๋ผ์ธ ์„ ํƒ (preprocessing, YOLO, OCR, Rule-based, HCX, all)" + ) + args = parser.parse_args() + + with open(args.config, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + if args.pipeline in ["preprocessing", "all"]: + run_pipeline("preprocessing", config) + if args.pipeline in ["YOLO", "all"]: + run_pipeline("YOLO", config) + if args.pipeline in ["OCR", "all"]: + run_pipeline("OCR", config) + if args.pipeline in ["Rule-based", "all"]: + run_pipeline("Rule-based", config) + if args.pipeline in ["HCX", "all"]: + run_pipeline("HCX", config) + +if __name__ == "__main__": + main() diff --git a/models/nutrition_ingredients_information/prompt/system_prompt_vf.txt b/models/nutrition_ingredients_information/prompt/system_prompt_vf.txt new file mode 100644 index 0000000..9a5f385 --- /dev/null +++ b/models/nutrition_ingredients_information/prompt/system_prompt_vf.txt @@ -0,0 +1 @@ +๋‹น์‹ ์€ ํ‘œ ํ˜•ํƒœ์˜ OCR ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์‹ํ’ˆ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋ˆ„๋ฝ ์—†์ด "ํ•ญ๋ชฉ: ๋‚ด์šฉ" ์Œ์œผ๋กœ ๋งคํ•‘ํ•˜๊ณ , ๋ฐ˜๋“œ์‹œ JSON ํ˜•์‹์œผ๋กœ๋งŒ ์ถœ๋ ฅํ•˜์„ธ์š”. \ No newline at end of file diff --git a/models/nutrition_ingredients_information/prompt/user_prompt_vf.txt b/models/nutrition_ingredients_information/prompt/user_prompt_vf.txt new file mode 100644 index 0000000..b29425a --- /dev/null +++ b/models/nutrition_ingredients_information/prompt/user_prompt_vf.txt @@ -0,0 +1,20 @@ +[์‹ํ’ˆ์ •๋ณด]๋Š” OCR๋กœ ์ธ์‹๋œ ์‹ํ’ˆ์˜ ์„ฑ๋ถ„ํ‘œ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. +(ํ–‰,์—ด) ํ˜•์‹์€ ํ‘œ์˜ ์œ„์น˜ ์ •๋ณด์ด๋ฉฐ, ์˜ˆ์ปจ๋Œ€ (1,2)๋Š” 1ํ–‰ 2์—ด์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. (ํ–‰,์—ด) ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ œ์‹œ๋œ [์‹ํ’ˆ์ •๋ณด]๋ฅผ ๋ถ„์„ํ•˜์„ธ์š”. +๋ถ„์„ ๊ฒฐ๊ณผ๋Š” JSON ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ, ์š”๊ตฌ๋œ ํ•ญ๋ชฉ ์ค‘ ํŠน์ • ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ „ํ˜€ ์—†์„ ๊ฒฝ์šฐ "์—†์Œ"์ด๋ผ๊ณ  ์ž‘์„ฑํ•˜์„ธ์š”. + +[์ถ”์ถœํ•ด์•ผ ํ•  ํ•ญ๋ชฉ] +1. ์›์žฌ๋ฃŒ: ๊ฐ๊ฐ์˜ ์›์žฌ๋ฃŒ๋ฅผ ๋ฐฐ์—ด(๋ฆฌ์ŠคํŠธ) ํ˜•ํƒœ๋กœ ๋‚˜๋ˆ„์–ด ๊ธฐ์žฌํ•˜์„ธ์š”. (์˜ˆ: ["๋ฌด 98.13%(๊ตญ์‚ฐ)", "์ฒœ์ผ์—ผ(ํ˜ธ์ฃผ์‚ฐ)", "๋น™์ดˆ์‚ฐ", ...]) +2. ์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ): ์ œํ’ˆ์— ์‹ค์ œ๋กœ ํ•จ์œ ๋˜์–ด ์•Œ๋ ˆ๋ฅด๊ธฐ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌผ์งˆ์„ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๊ธฐ์žฌํ•˜์„ธ์š”. (์˜ˆ: ["์šฐ์œ ", "๋ฉ”๋ฐ€", ...]) + - ํ‘œ์‹œ๋Œ€์ƒ ์•Œ๋ ˆ๋ฅด๊ธฐ ์œ ๋ฐœ ๋ฌผ์งˆ: ์•Œ๋ฅ˜(๊ณ„๋ž€), ์šฐ์œ , ๋ฉ”๋ฐ€, ๋•…์ฝฉ, ๋Œ€๋‘, ๋ฐ€, ์žฃ, ํ˜ธ๋‘, ๊ฒŒ, ์ƒˆ์šฐ, ์˜ค์ง•์–ด, ๊ณ ๋“ฑ์–ด, ์กฐ๊ฐœ๋ฅ˜, ๋ณต์ˆญ์•„, ํ† ๋งˆํ† , ๋‹ญ๊ณ ๊ธฐ, ๋ผ์ง€๊ณ ๊ธฐ, ์‡ ๊ณ ๊ธฐ, ์•„ํ™ฉ์‚ฐ๋ฅ˜ +3. ์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ): ๊ฐ™์€ ์ œ์กฐ ๊ณต์ •์—์„œ ์ƒ์‚ฐ๋˜์–ด ํ˜ผ์ž… ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ์•Œ๋ ˆ๋ฅด๊ธฐ ๋ฌผ์งˆ์„ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๊ธฐ์žฌํ•˜์„ธ์š”. (์˜ˆ: ["์šฐ์œ ", "๋ฉ”๋ฐ€", ...]) +4. ๋ณด๊ด€๋ฐฉ๋ฒ•: ๊ฐœ๋ด‰์ „, ๊ฐœ๋ด‰ํ›„ (์˜ˆ: "์ง์‚ฌ๊ด‘์„ ์„ ํ”ผํ•˜๊ณ  ์„œ๋Š˜ํ•œ ๊ณณ์— ๋ณด๊ด€ํ•˜์‹ญ์‹œ์˜ค", "0~10โ„ƒ์—์„œ ๋ƒ‰์žฅ๋ณด๊ด€" ๋“ฑ) + +[์ง€์‹œ์‚ฌํ•ญ] +1. ํ–‰๊ณผ ์—ด ์ •๋ณด๋ฅผ ํžŒํŠธ๋กœ ํ™œ์šฉํ•ด, ํ‘œ์— ๊ธฐ์žฌ๋œ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ๋น ์ง์—†์ด ์ถ”์ถœํ•˜์„ธ์š”. +2. ํ‘œ์— ๊ณต๋ฐฑ์ด๋‚˜ ๋„์–ด์“ฐ๊ธฐ๊ฐ€ ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒฝ์šฐ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ˆ˜์ •ํ•˜๋˜, ์ฃผ์š” ๋‹จ์–ด์™€ ๋‚ด์šฉ์€ ์ ˆ๋Œ€ ์ž„์˜๋กœ ๋ณ€๊ฒฝํ•˜์ง€ ๋งˆ์„ธ์š”. +3. ์ตœ์ข… ์ถœ๋ ฅ์€ ๋ฐ˜๋“œ์‹œ JSON ํ˜•ํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ํ•ญ๋ชฉ๋ณ„ "ํ‚ค: ๊ฐ’" ์Œ์œผ๋กœ ๊ตฌ์„ฑํ•˜์„ธ์š”. +4. ํ•ญ๋ชฉ๋ณ„ ์ •๋ณด๊ฐ€ ์—ฌ๋Ÿฌ ์ค„๋กœ ๋ถ„์‚ฐ๋ผ ์žˆ๋‹ค๋ฉด ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ, ์œ„์—์„œ ์•„๋ž˜๋กœ ์ •๋ณด๋ฅผ ํ•ฉ์ณ์„œ ํ•˜๋‚˜์˜ ํ•ญ๋ชฉ์œผ๋กœ ๊ตฌ์„ฑํ•˜์„ธ์š”. +5. ํŠน์ • ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ „ํ˜€ ์—†์œผ๋ฉด "์—†์Œ"์ด๋ผ๊ณ  ์ž‘์„ฑํ•˜์„ธ์š”. + +[์‹ํ’ˆ์ •๋ณด] +{ocr_data} diff --git a/models/nutrition_ingredients_information/src/HCX/01_HCX_dataset.py b/models/nutrition_ingredients_information/src/HCX/01_HCX_dataset.py new file mode 100644 index 0000000..678104c --- /dev/null +++ b/models/nutrition_ingredients_information/src/HCX/01_HCX_dataset.py @@ -0,0 +1,36 @@ +import pandas as pd + +# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • +prompt_file = "prompt/user_prompt_vf.txt" +completion_file = "data/HCX/train/HCX_273_gpt_processed_v2.csv" +output_file = "data/HCX/train/HCX_train_v2.csv" + +# ํ…์ŠคํŠธ ํŒŒ์ผ์—์„œ ์ „์ฒด ํ”„๋กฌํ”„ํŠธ ๋กœ๋“œ +with open(prompt_file, "r", encoding="utf-8") as f: + prompt_template = f.read().strip() + +# CSV ํŒŒ์ผ์—์„œ Completion ๋ฐ OCR ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ ๋กœ๋“œ +completion_df = pd.read_csv(completion_file, encoding="utf-8") + +# reference ๋ฐ ocr_data ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ ์ถ”์ถœ (NaN ๊ฐ’ ์ œ๊ฑฐ) +completions = completion_df["reference"].dropna().tolist() +ocr_results = completion_df["ocr_data"].dropna().tolist() + +# ๋ฐ์ดํ„ฐ ํฌ๊ธฐ๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•ด ์„ธ ๋ฆฌ์ŠคํŠธ ์ค‘ ์ตœ์†Œ ๊ธธ์ด์— ๋งž์ถค +min_length = min(len(completions), len(ocr_results)) + +# ํ”„๋กฌํ”„ํŠธ ๋‚ด {ocr_data}๋ฅผ ๊ฐ ocr_data ๊ฐ’์œผ๋กœ ์น˜ํ™˜ํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ +processed_prompts = [ + prompt_template.replace("{ocr_data}", str(ocr_results[i])) for i in range(min_length) +] + +# ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ ์ƒ์„ฑ +df = pd.DataFrame({ + "C_ID": list(range(min_length)), + "T_ID": [0] * min_length, + "Text": processed_prompts, + "Completion": completions[:min_length] +}) + +# CSV ํŒŒ์ผ๋กœ ์ €์žฅ +df.to_csv(output_file, index=False, encoding="utf-8") diff --git a/models/nutrition_ingredients_information/src/HCX/02_HCX_train.py b/models/nutrition_ingredients_information/src/HCX/02_HCX_train.py new file mode 100644 index 0000000..5084132 --- /dev/null +++ b/models/nutrition_ingredients_information/src/HCX/02_HCX_train.py @@ -0,0 +1,48 @@ +import requests + +class CreateTaskExecutor: + def __init__(self, host, uri, api_key, request_id): + self._host = host + self._uri = uri + self._api_key = api_key + self._request_id = request_id + + def _send_request(self, create_request): + + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id + } + result = requests.post(self._host + self._uri, json=create_request, headers=headers).json() + return result + + def execute(self, create_request): + res = self._send_request(create_request) + if 'status' in res and res['status']['code'] == '20000': + return res['result'] + else: + return res + + +if __name__ == '__main__': + completion_executor = CreateTaskExecutor( + host='https://clovastudio.stream.ntruss.com', + uri='/tuning/v2/tasks', + api_key='YOUR_API_KEY', + request_id='YOUR_REQUEST_ID' + ) + + request_data = {'name': 'ingredient_v2', + 'model': 'HCX-003', + 'tuningType': 'PEFT', + 'taskType': 'GENERATION', + 'trainEpochs': '8', + 'learningRate': '1e-5f', + 'trainingDatasetBucket': 'itsmenlp', + 'trainingDatasetFilePath': 'HCX_train_v2.csv', + 'trainingDatasetAccessKey': 'ncp_iam_BPASKR3PW1KUY1rvcqmp', + 'trainingDatasetSecretKey': 'ncp_iam_BPKSKRVIk5hfJHkuTkdHPEs0gDqix90kdV' + } + response_text = completion_executor.execute(request_data) + print(request_data) + print(response_text) diff --git a/models/nutrition_ingredients_information/src/HCX/03_HCX_inference.py b/models/nutrition_ingredients_information/src/HCX/03_HCX_inference.py new file mode 100644 index 0000000..882111c --- /dev/null +++ b/models/nutrition_ingredients_information/src/HCX/03_HCX_inference.py @@ -0,0 +1,102 @@ +import requests +import pandas as pd + +import time + +class TuningModelInference: + def __init__(self, host, api_key, request_id, taskId): + self.host = host + self.api_key = api_key + self.request_id = request_id + self.taskId = taskId + + def infer(self, system_message, user_message): + headers = { + 'Authorization': self.api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self.request_id, + 'Content-Type': 'application/json; charset=utf-8', + } + + data = { + "messages": [ + {"role": "system", "content": system_message}, + {"role": "user", "content": user_message} + ], + "temperature": 0.5, + "topK": 0, + "topP": 0.8, + "maxTokens": 1024, + "repeatPenalty": 5.0, + "includeAiFilters": True, + "stopBefore": [] + } + + for attempt in range(20): + try: + start_time = time.time() + with requests.post(self.host + f'/testapp/v2/tasks/{self.taskId}/chat-completions', headers=headers, json=data) as r: + elapsed_time = time.time() - start_time + response = r.json() + + # 'status'๊ฐ€ OK์ด๋ฉด 'message' ์•ˆ์˜ 'content'๋ฅผ ์ถ”์ถœ + if response.get("status", {}).get("code") == "20000": + return response["result"]["message"]["content"], elapsed_time + else: + raise ValueError(f"Invalid status code: {response.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < 20 - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. 10์ดˆ ํ›„ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. (์‹œ๋„ {attempt + 1}/20)") + time.sleep(10) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ 20ํšŒ๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None, None + + return None, None + +# ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ +def read_file(filename): + with open(filename, 'r', encoding='utf-8') as file: + return file.read().strip() + +# CSV์—์„œ OCR ๋ฐ์ดํ„ฐ ๋ฐ img-ID ๋กœ๋“œ +def load_ocr_data(csv_filename): + df = pd.read_csv(csv_filename) + if 'OCR ๊ฒฐ๊ณผ' not in df.columns or 'img-ID' not in df.columns: + raise ValueError("CSV ํŒŒ์ผ์— 'OCR ๊ฒฐ๊ณผ' ๋˜๋Š” 'img-ID' ์—ด์ด ์—†์Šต๋‹ˆ๋‹ค.") + return df[['img-ID', 'OCR ๊ฒฐ๊ณผ']].to_dict('records') + +if __name__ == '__main__': + # API ์ธ์ฆ ์ •๋ณด + host='https://clovastudio.stream.ntruss.com' + api_key='YOUR_API_KEY' + request_id='YOUR_REQUEST_ID' + taskId = '5s8l73ye' + + # ํŒŒ์ผ์—์„œ ๋ฉ”์‹œ์ง€ ์ฝ๊ธฐ + system_message = read_file('prompt/system_prompt_vf.txt') + user_message_template = read_file('prompt/user_prompt_vf.txt') + + # CSV์—์„œ OCR ๋ฐ์ดํ„ฐ ๋ฐ img-ID ๋กœ๋“œ + ocr_data_list = load_ocr_data('data/OCR/inference/images_323_OCR_row_col.csv') + + # ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰ + inference = TuningModelInference(host, api_key, request_id, taskId) + + results = [] + for idx, data in enumerate(ocr_data_list): + img_id = data['img-ID'] + ocr_data = data['OCR ๊ฒฐ๊ณผ'] + + # OCR ๋ฐ์ดํ„ฐ ์‚ฝ์ž… + user_message = user_message_template.replace("{ocr_data}", ocr_data) + + # API ์š”์ฒญ ๋ฐ ์‘๋‹ต ์ €์žฅ + response_text = inference.infer(system_message, user_message) + results.append({"img-ID": img_id, "์„ฑ๋ถ„์ •๋ณด": response_text}) + + # ์ง„ํ–‰ ์ƒํ™ฉ ์ถœ๋ ฅ + print(f"[{idx+1}/{len(ocr_data_list)}] ์š”์ฒญ ์™„๋ฃŒ - img-ID: {img_id}") + + # ๊ฒฐ๊ณผ ์ €์žฅ + result_df = pd.DataFrame(results) + result_df.to_csv("data/HCX/inference/HCX_inference_v2.csv", index=False, encoding="utf-8-sig") diff --git a/models/nutrition_ingredients_information/src/HCX/04_post_processing.py b/models/nutrition_ingredients_information/src/HCX/04_post_processing.py new file mode 100644 index 0000000..3d13d83 --- /dev/null +++ b/models/nutrition_ingredients_information/src/HCX/04_post_processing.py @@ -0,0 +1,74 @@ +import pandas as pd +import ast +import json +import re + +# CSV ํŒŒ์ผ ๋กœ๋“œ +file_path = "data/HCX/inference/HCX_inference_v2.csv" +df = pd.read_csv(file_path) + +# ์„ฑ๋ถ„์ •๋ณด ์ปฌ๋Ÿผ JSON ๋ณ€ํ™˜ ํ•จ์ˆ˜ +def clean_json_format(value): + try: + # ํŠœํ”Œ ํ˜•์‹์ด๋ฉด ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋งŒ ์ถ”์ถœ + if isinstance(value, str) and value.startswith("('{"): + value = ast.literal_eval(value)[0] # ํŠœํ”Œ์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ + + # JSON ๋ฌธ์ž์—ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ€ํ™˜ + cleaned_json = json.loads(value) + return json.dumps(cleaned_json, ensure_ascii=False) + except Exception as e: + return value # ๋ณ€ํ™˜ ์‹คํŒจ ์‹œ ์›๋ณธ ๊ฐ’ ์œ ์ง€ + +# ๋ณ€ํ™˜ ์ ์šฉ +df["์„ฑ๋ถ„์ •๋ณด"] = df["์„ฑ๋ถ„์ •๋ณด"].apply(clean_json_format) + +# JSON ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ ๊ฐœ๋ณ„ ์ปฌ๋Ÿผ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ +def parse_json(json_str): + try: + # ๋ฌธ์ž์—ด ํ™•์ธ ํ›„ JSON ๋ณ€ํ™˜ ์‹œ๋„ + if isinstance(json_str, str): + data = json.loads(json_str.replace("'", "\"")) # ์ž‘์€๋”ฐ์˜ดํ‘œ ๋ณ€ํ™˜ ํ›„ JSON ๋กœ๋“œ + else: + return pd.Series(["์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜"]) + + # ์›์žฌ๋ฃŒ ๋ฐ ์•Œ๋ ˆ๋ฅด๊ธฐ ์ •๋ณด ์ถ”์ถœ + ์›์žฌ๋ฃŒ = ", ".join(data.get("์›์žฌ๋ฃŒ", [])) if isinstance(data.get("์›์žฌ๋ฃŒ"), list) else "" + ์•Œ๋ ˆ๋ฅด๊ธฐ_1์ฐจ = ", ".join(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", [])) if isinstance(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)"), list) else "" + ์•Œ๋ ˆ๋ฅด๊ธฐ_2์ฐจ = ", ".join(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)", [])) if isinstance(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)"), list) else "" + + # ๋ณด๊ด€๋ฐฉ๋ฒ•์„ ๋ฌธ์ž์—ด ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์˜ค๊ณ , ํ•„์š”ํ•œ ๊ฐ’๋งŒ ์ถ”์ถœ + ๋ณด๊ด€๋ฐฉ๋ฒ•_raw = str(data.get("๋ณด๊ด€๋ฐฉ๋ฒ•", "{}")) # dict -> str ๋ณ€ํ™˜ + + # ์•ˆ์ „ํ•˜๊ฒŒ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ณ€ํ™˜ ์‹œ๋„ + try: + ๋ณด๊ด€๋ฐฉ๋ฒ•_dict = ast.literal_eval(๋ณด๊ด€๋ฐฉ๋ฒ•_raw) if "{" in ๋ณด๊ด€๋ฐฉ๋ฒ•_raw else {} + except (ValueError, SyntaxError): + ๋ณด๊ด€๋ฐฉ๋ฒ•_dict = {} + + ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰์ „ = ๋ณด๊ด€๋ฐฉ๋ฒ•_dict.get("๊ฐœ๋ด‰์ „", "") if isinstance(๋ณด๊ด€๋ฐฉ๋ฒ•_dict, dict) else "" + ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰ํ›„ = ๋ณด๊ด€๋ฐฉ๋ฒ•_dict.get("๊ฐœ๋ด‰ํ›„", "") if isinstance(๋ณด๊ด€๋ฐฉ๋ฒ•_dict, dict) else "" + + return pd.Series([์›์žฌ๋ฃŒ, ์•Œ๋ ˆ๋ฅด๊ธฐ_1์ฐจ, ์•Œ๋ ˆ๋ฅด๊ธฐ_2์ฐจ, ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰์ „, ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰ํ›„]) + + except (json.JSONDecodeError, TypeError): + # JSON ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ๋ฐ˜ํ™˜ + return pd.Series(["์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜"]) + +# 'reference' ์ปฌ๋Ÿผ์˜ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐœ๋ณ„ ์ปฌ๋Ÿผ์œผ๋กœ ๋ณ€ํ™˜ +df[["์›์žฌ๋ฃŒ", "์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", "์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„)"]] = df["์„ฑ๋ถ„์ •๋ณด"].apply(parse_json) + +# ------------------------- +def extract_number_from_img_id(img_id): + match = re.search(r'-(\d+)-', img_id) + return int(match.group(1)) if match else float('inf') + +df['์ •๋ ฌ๋ฒˆํ˜ธ'] = df['img-ID'].apply(lambda x: extract_number_from_img_id(str(x))) +df.sort_values(by='์ •๋ ฌ๋ฒˆํ˜ธ', ascending=True, inplace=True) +# ------------------------- + +# ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ๋‚จ๊ธฐ๊ธฐ +df = df[["img-ID", "์›์žฌ๋ฃŒ", "์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", "์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„)"]] + +# ๋ณ€ํ™˜๋œ ๋ฐ์ดํ„ฐ ์ €์žฅ +df.to_csv("data/HCX/inference/images_323_ingredient.csv", index=False, encoding="utf-8-sig") diff --git a/models/nutrition_ingredients_information/src/HCX/05_eval_ingredient.py b/models/nutrition_ingredients_information/src/HCX/05_eval_ingredient.py new file mode 100644 index 0000000..b6fd897 --- /dev/null +++ b/models/nutrition_ingredients_information/src/HCX/05_eval_ingredient.py @@ -0,0 +1,47 @@ +import pandas as pd +import Levenshtein + +def compare_ingredient_files(file1, file2): + # CSV ํŒŒ์ผ ๋กœ๋“œ + df1 = pd.read_csv(file1) + df2 = pd.read_csv(file2) + + # ํ•„์š”ํ•œ ์ปฌ๋Ÿผ ์„ ํƒ + columns_to_compare = ['์›์žฌ๋ฃŒ', '์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)', '์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)', '๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „)', '๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„)'] + df1 = df1[['img-ID'] + columns_to_compare] + df2 = df2[['img-ID'] + columns_to_compare] + + # img-ID ๊ธฐ์ค€์œผ๋กœ ๋ณ‘ํ•ฉ + merged_df = pd.merge(df1, df2, on='img-ID', suffixes=('_50', '_323')) + + # NaN ๊ฐ’์„ ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ ํ›„ ๊ณต๋ฐฑ ์ œ๊ฑฐ + for col in columns_to_compare: + merged_df[f'{col}_50'] = merged_df[f'{col}_50'].fillna('').astype(str).str.replace(" ", "", regex=True) + merged_df[f'{col}_323'] = merged_df[f'{col}_323'].fillna('').astype(str).str.replace(" ", "", regex=True) + + # Levenshtein ๊ฑฐ๋ฆฌ ๋ฐ ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ + for col in columns_to_compare: + merged_df[f'Levenshtein_Distance_{col}'] = merged_df.apply( + lambda row: Levenshtein.distance(row[f'{col}_50'], row[f'{col}_323']), axis=1 + ) + + merged_df[f'Similarity_Ratio_{col}'] = merged_df.apply( + lambda row: Levenshtein.ratio(row[f'{col}_50'], row[f'{col}_323']), axis=1 + ) + + # ํ‰๊ท  ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ + avg_similarities = { + col: merged_df[f'Similarity_Ratio_{col}'].mean() for col in columns_to_compare + } + + # ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print(f'์ด ๋น„๊ต๋œ ํ•ญ๋ชฉ ์ˆ˜: {len(merged_df)}') + for col in columns_to_compare: + print(f'ํ‰๊ท  ์œ ์‚ฌ๋„ ({col}): {avg_similarities[col] * 100:.2f}%') + + return merged_df + +# ์‚ฌ์šฉ ์˜ˆ์‹œ +file1 = 'data/HCX/eval/images_50_ingredient_processed.csv' +file2 = 'data/HCX/inference/images_323_ingredient.csv' +result_df = compare_ingredient_files(file1, file2) diff --git a/models/nutrition_ingredients_information/src/OCR/01_OCR_text.py b/models/nutrition_ingredients_information/src/OCR/01_OCR_text.py new file mode 100644 index 0000000..a0c1aff --- /dev/null +++ b/models/nutrition_ingredients_information/src/OCR/01_OCR_text.py @@ -0,0 +1,134 @@ +import os +import csv +import json +import requests +from io import BytesIO +from PIL import Image +import pandas as pd +import re + +def clova_ocr(image_path, secret_key): + + url = "https://zpojzpbnkf.apigw.ntruss.com/custom/v1/37528/65e67b30b3cc8f4d84245194c2415f0c980675f1f0961dbfc2ecc51a368e238c/general" + + headers = {'X-OCR-SECRET': secret_key} + payload = { + 'message': json.dumps({ + "version": "v2", + "requestId": "1234", + "timestamp": 1722225600000, + "lang": "ko", + "enableTableDetection": "True", + "images": [{"format": "jpg", "name": os.path.basename(image_path)}] + }) + } + + with open(image_path, 'rb') as img_file: + files = {'file': (os.path.basename(image_path), img_file, 'image/jpeg')} + response = requests.post(url, headers=headers, data=payload, files=files) + + if response.status_code == 200: + return response.json() + else: + print(f"OCR ์š”์ฒญ ์‹คํŒจ! Status Code: {response.status_code}") + return None + +def extract_text_from_ocr_result(ocr_result): + + try: + text_list = [] + for image in ocr_result.get("images", []): + for field in image.get("fields", []): + text_list.append(field.get("inferText", "")) + return " ".join(text_list) + except Exception as e: + print(f"OCR ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {e}") + return "OCR ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ ์‹คํŒจ" + +def get_img_id(filename): + if filename == "emart35110.png": + return "emart-351-10" + + match = re.search(r'(emart)(\d+)(\d)(?=\.)', filename) + + if match: + return f"{match.group(1)}-{match.group(2)}-{match.group(3)}" + + return filename + +def crop_and_ocr(image_dir, label_dir, output_csv_path, secret_key): + + os.makedirs("temp_crop", exist_ok=True) # ์ž„์‹œ ํด๋” ์ƒ์„ฑ + image_extensions = ('.png', '.jpg', '.jpeg') + + image_files = [f for f in os.listdir(image_dir) if f.lower().endswith(image_extensions)] + df = pd.DataFrame({'img-ID': [get_img_id(f) for f in image_files], 'OCR ๊ฒฐ๊ณผ': ""}) + + for index, row in df.iterrows(): + image_filename = image_files[index] + image_path = os.path.join(image_dir, image_filename) + label_path = os.path.join(label_dir, image_filename.rsplit(".", 1)[0] + ".txt") + + if not os.path.exists(label_path): + print(f"๋ผ๋ฒจ ํŒŒ์ผ ์—†์Œ: {label_path}") + df.at[index, 'OCR ๊ฒฐ๊ณผ'] = "๋ผ๋ฒจ ํŒŒ์ผ ์—†์Œ" + continue + + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = Image.open(image_path) + img_width, img_height = image.size + + # YOLO ๊ฒฐ๊ณผ ์ฝ๊ธฐ + with open(label_path, 'r') as f: + lines = f.readlines() + + ocr_results = [] + + for i, line in enumerate(lines): + parts = line.strip().split() + if len(parts) != 5: + continue + + class_id, cx, cy, w, h = map(float, parts) + + # class_id๊ฐ€ 0์ด ์•„๋‹Œ ๊ฒฝ์šฐ ๊ฑด๋„ˆ๋œ€ + if int(class_id) != 0: + continue + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ ๋ณ€ํ™˜ (YOLO ์ •๊ทœํ™”๋œ ๊ฐ’ โ†’ ์‹ค์ œ ํ”ฝ์…€ ์ขŒํ‘œ) + x1 = int((cx - w / 2) * img_width) + y1 = int((cy - h / 2) * img_height) + x2 = int((cx + w / 2) * img_width) + y2 = int((cy + h / 2) * img_height) + + # ์ขŒํ‘œ ๊ฒ€์ฆ + if x1 < 0 or y1 < 0 or x2 > img_width or y2 > img_height or x2 <= x1 or y2 <= y1: + print(f"์ž˜๋ชป๋œ ์ขŒํ‘œ ์Šคํ‚ต: {x1}, {y1}, {x2}, {y2}") + continue + + # ์ด๋ฏธ์ง€ ํฌ๋กญ + cropped_img = image.crop((x1, y1, x2, y2)) + cropped_path = f"temp_crop/crop_{index}_{i}.jpg" + cropped_img.save(cropped_path) + + # OCR ์ˆ˜ํ–‰ + ocr_result = clova_ocr(cropped_path, secret_key) + if ocr_result: + extracted_text = extract_text_from_ocr_result(ocr_result) + ocr_results.append(extracted_text) + else: + ocr_results.append("OCR ์‹คํŒจ") + + os.remove(cropped_path) # OCR ํ›„ ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ + + df.at[index, 'OCR ๊ฒฐ๊ณผ'] = " | ".join(ocr_results) + + df.to_csv(output_csv_path, index=False, encoding='utf-8-sig') + +# OCR ์‹คํ–‰ +secret_key = 'YOUR_SECRET_KEY' +image_dir = 'data/YOLO/output/images/' +label_dir = 'data/YOLO/output/labels/' +output_csv_path = 'data/OCR/inference/images_323_OCR_text.csv' + +crop_and_ocr(image_dir, label_dir, output_csv_path, secret_key) diff --git a/models/nutrition_ingredients_information/src/OCR/02_OCR_row_col_323.py b/models/nutrition_ingredients_information/src/OCR/02_OCR_row_col_323.py new file mode 100644 index 0000000..24d1511 --- /dev/null +++ b/models/nutrition_ingredients_information/src/OCR/02_OCR_row_col_323.py @@ -0,0 +1,177 @@ +import os +import csv +import json +import requests +from io import BytesIO +from PIL import Image +import pandas as pd +import re + +def clova_ocr(image_path, secret_key): + + url = "https://zpojzpbnkf.apigw.ntruss.com/custom/v1/37528/65e67b30b3cc8f4d84245194c2415f0c980675f1f0961dbfc2ecc51a368e238c/general" + + headers = {'X-OCR-SECRET': secret_key} + payload = { + 'message': json.dumps({ + "version": "v2", + "requestId": "1234", + "timestamp": 1722225600000, + "lang": "ko", + "enableTableDetection": "True", + "images": [{"format": "jpg", "name": os.path.basename(image_path)}] + }) + } + + with open(image_path, 'rb') as img_file: + files = {'file': (os.path.basename(image_path), img_file, 'image/jpeg')} + response = requests.post(url, headers=headers, data=payload, files=files) + + if response.status_code == 200: + return response.json() + else: + print(f"OCR ์š”์ฒญ ์‹คํŒจ! Status Code: {response.status_code}") + return None + +def extract_grouped_text(ocr_data): + grouped_text = {} + + # ------------------------- + # 1) ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ + # ------------------------- + max_row_index = -1 # ํ…Œ์ด๋ธ” ์ค‘ ๊ฐ€์žฅ ํฐ rowIndex ํ™•์ธ์šฉ + for image in ocr_data.get("images", []): + for table in image.get("tables", []): + for cell in table.get("cells", []): + row = cell.get("rowIndex", 0) + col = cell.get("columnIndex", 0) + max_row_index = max(max_row_index, row) + + # ์ด ์…€์˜ ๋ชจ๋“  ๋‹จ์–ด๋ฅผ ํ•ฉ์นจ + cell_text = [] + for line in cell.get("cellTextLines", []): + for word in line.get("cellWords", []): + text = word.get("inferText", "") + if text: + cell_text.append(text) + + # "Row:x, Col:y" ํ˜•ํƒœ๋กœ ๋ฌถ์–ด์„œ ์ €์žฅ + key = f"({row},{col})" + if key not in grouped_text: + grouped_text[key] = [] + grouped_text[key].extend(cell_text) + + # ------------------------- + # 2) fields ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ + # ------------------------- + # ํ…Œ์ด๋ธ”์ด ํ•˜๋‚˜๋„ ์—†์—ˆ๋‹ค๋ฉด max_row_index = -1, fields๋Š” Row=0๋ถ€ํ„ฐ ์‹œ์ž‘ + field_row_index = max_row_index + 1 if max_row_index != -1 else 0 + + for image in ocr_data.get("images", []): + for field in image.get("fields", []): + infer_text = field.get("inferText", "") + if not infer_text: + continue + + # fields๋Š” (field_row_index, 0)์— ์ €์žฅ + key = f"({field_row_index},0)" + if key not in grouped_text: + grouped_text[key] = [] + grouped_text[key].append(infer_text) + + field_row_index += 1 # ๋‹ค์Œ ํ•„๋“œ ํ–‰์€ +1 + + # ------------------------- + # 3) row-col ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ๋ฐ˜ํ™˜ + # ------------------------- + def parse_key(k: str): + k = k.strip("()") + return tuple(map(int, k.split(','))) + + sorted_keys = sorted(grouped_text.keys(), key=parse_key) + grouped_text_sorted = {k: grouped_text[k] for k in sorted_keys} + return grouped_text_sorted + +def get_img_id(filename): + if filename == "emart35110.png": + return "emart-351-10" + + match = re.search(r'(emart)(\d+)(\d)(?=\.)', filename) + + if match: + return f"{match.group(1)}-{match.group(2)}-{match.group(3)}" + + return filename + +def crop_and_ocr(image_dir, label_dir, output_csv_path, secret_key): + + os.makedirs("temp_crop", exist_ok=True) # ์ž„์‹œ ํด๋” ์ƒ์„ฑ + image_extensions = ('.png', '.jpg', '.jpeg') + + image_files = [f for f in os.listdir(image_dir) if f.lower().endswith(image_extensions)] + df = pd.DataFrame({'img-ID': [get_img_id(f) for f in image_files], 'OCR ๊ฒฐ๊ณผ': ""}) + + for index, row in df.iterrows(): + image_filename = image_files[index] + image_path = os.path.join(image_dir, image_filename) + label_path = os.path.join(label_dir, image_filename.rsplit(".", 1)[0] + ".txt") + + if not os.path.exists(label_path): + print(f"๋ผ๋ฒจ ํŒŒ์ผ ์—†์Œ: {label_path}") + df.at[index, 'OCR ๊ฒฐ๊ณผ'] = "๋ผ๋ฒจ ํŒŒ์ผ ์—†์Œ" + continue + + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = Image.open(image_path) + img_width, img_height = image.size + + # YOLO ๊ฒฐ๊ณผ ์ฝ๊ธฐ + with open(label_path, 'r') as f: + lines = f.readlines() + + ocr_results = [] + + for i, line in enumerate(lines): + parts = line.strip().split() + if len(parts) != 5: + continue # YOLO ํ˜•์‹์ด ๋งž์ง€ ์•Š์œผ๋ฉด ์Šคํ‚ต + + class_id, cx, cy, w, h = map(float, parts) + + # class_id๊ฐ€ 1์ด ์•„๋‹Œ ๊ฒฝ์šฐ ๊ฑด๋„ˆ๋œ€ + if int(class_id) != 1: + continue + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ ๋ณ€ํ™˜ (YOLO ์ •๊ทœํ™”๋œ ๊ฐ’ โ†’ ์‹ค์ œ ํ”ฝ์…€ ์ขŒํ‘œ) + x1 = int((cx - w / 2) * img_width) + y1 = int((cy - h / 2) * img_height) + x2 = int((cx + w / 2) * img_width) + y2 = int((cy + h / 2) * img_height) + + # ์ขŒํ‘œ ๊ฒ€์ฆ + if x1 < 0 or y1 < 0 or x2 > img_width or y2 > img_height or x2 <= x1 or y2 <= y1: + print(f"์ž˜๋ชป๋œ ์ขŒํ‘œ ์Šคํ‚ต: {x1}, {y1}, {x2}, {y2}") + continue + + # ์ด๋ฏธ์ง€ ํฌ๋กญ + cropped_img = image.crop((x1, y1, x2, y2)) + cropped_path = f"temp_crop/crop_{index}_{i}.jpg" + cropped_img.save(cropped_path) + + # OCR ์ˆ˜ํ–‰ + ocr_data = clova_ocr(cropped_path, secret_key) + grouped_result = extract_grouped_text(ocr_data) + for key, value in grouped_result.items(): + grouped_result[key] = " ".join(value) + + df.at[index, 'OCR ๊ฒฐ๊ณผ'] = json.dumps(grouped_result, ensure_ascii=False) + + df.to_csv(output_csv_path, index=False, encoding='utf-8-sig') + +# OCR ์‹คํ–‰ +secret_key = 'YOUR_SECRET_KEY' +image_dir = 'data/YOLO/output/images/' +label_dir = 'data/YOLO/output/labels/' +output_csv_path = 'data/OCR/inference/images_323_OCR_row_col.csv' + +crop_and_ocr(image_dir, label_dir, output_csv_path, secret_key) diff --git a/models/nutrition_ingredients_information/src/OCR/03_OCR_row_col_273_50.py b/models/nutrition_ingredients_information/src/OCR/03_OCR_row_col_273_50.py new file mode 100644 index 0000000..7842b3d --- /dev/null +++ b/models/nutrition_ingredients_information/src/OCR/03_OCR_row_col_273_50.py @@ -0,0 +1,14 @@ +import pandas as pd + +# CSV ํŒŒ์ผ ๋กœ๋“œ +images_323_OCR = pd.read_csv('data/OCR/inference/images_323_OCR_row_col.csv') +images_273 = pd.read_csv("data/preprocessed/images_273.csv") +images_50 = pd.read_csv("data/preprocessed/images_50.csv") + +# img-ID ์ปฌ๋Ÿผ์„ ๊ธฐ์ค€์œผ๋กœ ํ•„ํ„ฐ๋ง +filtered_data_273 = images_323_OCR[images_323_OCR['img-ID'].isin(images_273['img-ID'])] +filtered_data_50 = images_323_OCR[images_323_OCR['img-ID'].isin(images_50['img-ID'])] + +# ๊ฒฐ๊ณผ๋ฅผ ์ƒˆ๋กœ์šด CSV ํŒŒ์ผ๋กœ ์ €์žฅ +filtered_data_273.to_csv("data/OCR/inference/images_273_OCR_row_col.csv", index=False) +filtered_data_50.to_csv("data/OCR/inference/images_50_OCR_row_col.csv", index=False) diff --git a/models/nutrition_ingredients_information/src/Rule-based/01_rule_based.py b/models/nutrition_ingredients_information/src/Rule-based/01_rule_based.py new file mode 100644 index 0000000..fb9c089 --- /dev/null +++ b/models/nutrition_ingredients_information/src/Rule-based/01_rule_based.py @@ -0,0 +1,67 @@ +import re +import pandas as pd + +csv_file_path = 'data/OCR/inference/images_323_OCR_text.csv' +df = pd.read_csv(csv_file_path) + +def extract_nutrition_info(text): + if pd.notnull(text): + pattern_g = r'\d+\.?\d*\s*g(?=.*๋‚˜ํŠธ๋ฅจ)' + pattern_ml = r'\d+\.?\d*\s*ml(?=.*๋‚˜ํŠธ๋ฅจ)' + pattern_mL = r'\d+\.?\d*\s*mL(?=.*๋‚˜ํŠธ๋ฅจ)' + pattern_kcal = r'\d+\.?\d*\s*kcal(?=.*๋‚˜ํŠธ๋ฅจ)' + pattern_sodium = r'๋‚˜ํŠธ๋ฅจ.*?g' + pattern_carb = r'ํƒ„์ˆ˜ํ™”๋ฌผ.*?g' + pattern_sugar = r'๋‹น๋ฅ˜.*?g' + pattern_fat = r'์ง€๋ฐฉ.*?g' + pattern_trans_fat = r'ํŠธ๋žœ์Šค์ง€๋ฐฉ.*?g' + pattern_saturated_fat = r'ํฌํ™”์ง€๋ฐฉ.*?g' + pattern_cholesterol = r'์ฝœ๋ ˆ์Šคํ…Œ๋กค.*?g' + pattern_protein = r'๋‹จ๋ฐฑ์งˆ.*?g' + + match_g = re.search(pattern_g, text) + match_ml = re.search(pattern_ml, text) + match_mL = re.search(pattern_mL, text) + match_kcal = re.search(pattern_kcal, text) + match_sodium = re.search(pattern_sodium, text) + match_carb = re.search(pattern_carb, text) + match_sugar = re.search(pattern_sugar, text) + match_fat = re.search(pattern_fat, text) + match_trans_fat = re.search(pattern_trans_fat, text) + match_saturated_fat = re.search(pattern_saturated_fat, text) + match_cholesterol = re.search(pattern_cholesterol, text) + match_protein = re.search(pattern_protein, text) + + nutrition_info = [ + match_g.group(0) if match_g else '', + match_ml.group(0) if match_ml else '', + match_mL.group(0) if match_mL else '', + match_kcal.group(0) if match_kcal else '', + match_sodium.group(0) if match_sodium else '', + match_carb.group(0) if match_carb else '', + match_sugar.group(0) if match_sugar else '', + match_fat.group(0) if match_fat else '', + match_trans_fat.group(0) if match_trans_fat else '', + match_saturated_fat.group(0) if match_saturated_fat else '', + match_cholesterol.group(0) if match_cholesterol else '', + match_protein.group(0) if match_protein else '' + ] + + return ', '.join(filter(None, nutrition_info)) if any(nutrition_info) else None + + return None + +df['์˜์–‘์ •๋ณด'] = df['OCR ๊ฒฐ๊ณผ'].apply(lambda x: extract_nutrition_info(x)) + +# ------------------------- +def extract_number_from_img_id(img_id): + match = re.search(r'-(\d+)-', img_id) + return int(match.group(1)) if match else float('inf') + +df['์ •๋ ฌ๋ฒˆํ˜ธ'] = df['img-ID'].apply(lambda x: extract_number_from_img_id(str(x))) +df.sort_values(by='์ •๋ ฌ๋ฒˆํ˜ธ', ascending=True, inplace=True) +df.drop(columns=['์ •๋ ฌ๋ฒˆํ˜ธ', 'OCR ๊ฒฐ๊ณผ'], inplace=True) +# ------------------------- + +output_csv_path = 'data/Rule-based/inference/images_323_nutrition.csv' +df.to_csv(output_csv_path, index=False) diff --git a/models/nutrition_ingredients_information/src/Rule-based/02_eval_nutrition.py b/models/nutrition_ingredients_information/src/Rule-based/02_eval_nutrition.py new file mode 100644 index 0000000..a23feef --- /dev/null +++ b/models/nutrition_ingredients_information/src/Rule-based/02_eval_nutrition.py @@ -0,0 +1,72 @@ +import pandas as pd +import re + +# ์˜์–‘ ์ •๋ณด ์ถ”์ถœ ํ•จ์ˆ˜ +def extract_nutrition_info(text): + if pd.notnull(text): + patterns = { + "sodium": r'๋‚˜ํŠธ๋ฅจ.*?g', + "carb": r'ํƒ„์ˆ˜ํ™”๋ฌผ.*?g', + "sugar": r'๋‹น๋ฅ˜.*?g', + "fat": r'์ง€๋ฐฉ.*?g', + "trans_fat": r'ํŠธ๋žœ์Šค์ง€๋ฐฉ.*?g', + "saturated_fat": r'ํฌํ™”์ง€๋ฐฉ.*?g', + "cholesterol": r'์ฝœ๋ ˆ์Šคํ…Œ๋กค.*?g', + "protein": r'๋‹จ๋ฐฑ์งˆ.*?g' + } + + extracted_values = {} + for key, pattern in patterns.items(): + match = re.search(pattern, text) + if match: + extracted_values[key] = re.sub(r'\s+', '', match.group(0)) # ๊ณต๋ฐฑ ์ œ๊ฑฐ + else: + extracted_values[key] = None + + return extracted_values + + return {key: None for key in patterns.keys()} + +# CSV ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ +images_df = pd.read_csv("data/Rule-based/inference/images_323_nutrition.csv") +total_df = pd.read_csv("data/Rule-based/eval/total_nutrition.csv") + +# img-ID์—์„œ ๋งˆ์ง€๋ง‰ ๋‘ ๊ธ€์ž ์ œ๊ฑฐํ•˜์—ฌ ID ์ปฌ๋Ÿผ ์ถ”๊ฐ€ +images_df["ID"] = images_df["img-ID"].astype(str).str[:-2] + +# ID๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‘ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๋ณ‘ํ•ฉ +merged_df = pd.merge(images_df, total_df, on="ID", how="inner") + +# ์˜์–‘ ์ •๋ณด ์ถ”์ถœ (๊ฐ ๊ฐœ๋ณ„ ๊ฐ’ ๋น„๊ต) +merged_df["Extracted_Nutrition_images"] = merged_df["์˜์–‘์ •๋ณด_x"].apply(extract_nutrition_info) +merged_df["Extracted_Nutrition_total"] = merged_df["์˜์–‘์ •๋ณด_y"].apply(extract_nutrition_info) + +# ๊ฐ ์˜์–‘์†Œ๋ณ„ ๋น„๊ตํ•˜์—ฌ ์ผ์น˜ํ•˜๋ฉด 1, ๋‹ค๋ฅด๋ฉด 0 +nutrition_keys = ["sodium", "carb", "sugar", "fat", "trans_fat", "saturated_fat", "cholesterol", "protein"] + +for key in nutrition_keys: + merged_df[f"Match_{key}"] = merged_df.apply( + lambda row: 1 if row["Extracted_Nutrition_images"][key] == row["Extracted_Nutrition_total"][key] else 0, + axis=1 + ) + +# ์ดํ•ฉ ๊ณ„์‚ฐ +merged_df["Total_Match"] = merged_df[[f"Match_{key}" for key in nutrition_keys]].sum(axis=1) + +# ์ „์ฒด ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ +total_count = len(merged_df) + +# ์ด ์ผ์น˜ ๊ฐœ์ˆ˜ +total_match_count = merged_df['Total_Match'].sum() + +# ๊ฐ ํ•ญ๋ชฉ๋ณ„ ์ผ์น˜ ๊ฐœ์ˆ˜ ๋ฐ ํ™•๋ฅ  ๊ณ„์‚ฐ +match_summary = merged_df[[f"Match_{key}" for key in nutrition_keys]].sum() +match_percentage = (match_summary / total_count) * 100 + +total_match_percentage = (total_match_count / (total_count * len(nutrition_keys))) * 100 + +# ๊ฒฐ๊ณผ ์ถœ๋ ฅ +print(f"์ „์ฒด {total_count * len(nutrition_keys)}๊ฐœ ์ค‘ {total_match_count}๊ฐœ ์ผ์น˜") +print(f"์ด ์ผ์น˜ ํ™•๋ฅ : {total_match_percentage:.2f}%") +print("๊ฐ ํ•ญ๋ชฉ๋ณ„ ์ผ์น˜ ๊ฐœ์ˆ˜ ๋ฐ ํ™•๋ฅ :") +print(pd.DataFrame({"์ผ์น˜ ๊ฐœ์ˆ˜": match_summary, "์ผ์น˜ ํ™•๋ฅ (%)": match_percentage})) diff --git a/models/nutrition_ingredients_information/src/YOLO/01_data_conversion.py b/models/nutrition_ingredients_information/src/YOLO/01_data_conversion.py new file mode 100644 index 0000000..7347d3b --- /dev/null +++ b/models/nutrition_ingredients_information/src/YOLO/01_data_conversion.py @@ -0,0 +1,48 @@ +import pandas as pd +import os +import re +import requests + +# CSV ํŒŒ์ผ ์ฝ๊ธฐ +def load_csv(file_path): + return pd.read_csv(file_path, dtype=str) + +# ์ €์žฅ ํด๋” ์ƒ์„ฑ +def create_folder(folder_path): + os.makedirs(folder_path, exist_ok=True) + +# ํŒŒ์ผ๋ช… ์ •๋ฆฌ ํ•จ์ˆ˜ +def clean_filename(filename): + return re.sub(r"[^\w๊ฐ€-ํžฃ]", "", filename) + +# ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์ €์žฅ +def download_images(data, download_folder): + create_folder(download_folder) + + for index, row in data.iterrows(): + image_url = row["์ด๋ฏธ์ง€ URL"] + product_name = clean_filename(row["img-ID"]) + ".png" + save_path = os.path.join(download_folder, product_name) + + try: + response = requests.get(image_url, stream=True) + if response.status_code == 200: + with open(save_path, "wb") as file: + for chunk in response.iter_content(1024): + file.write(chunk) + print(f"Saved: {save_path}") + else: + print(f"Failed to download {image_url}") + except Exception as e: + print(f"Error downloading {image_url}: {e}") + +# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • +file_paths = { + "data/preprocessed/images_323.csv": "data/YOLO/inference/images", + "data/preprocessed/images_273.csv": "data/YOLO/train/images" +} + +# ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์‹คํ–‰ +for file_path, folder in file_paths.items(): + data = load_csv(file_path) + download_images(data, folder) diff --git a/models/nutrition_ingredients_information/src/YOLO/02_YOLO.py b/models/nutrition_ingredients_information/src/YOLO/02_YOLO.py new file mode 100644 index 0000000..78a100e --- /dev/null +++ b/models/nutrition_ingredients_information/src/YOLO/02_YOLO.py @@ -0,0 +1,65 @@ +from ultralytics import YOLO +import os +import torch +import cv2 + +# Load a trained model +model_path = "src/YOLO/yolo11n.pt" +if not os.path.exists(model_path): + raise FileNotFoundError(f"Model file '{model_path}' not found.") + +model = YOLO(model_path) + +# Train the model +train_results = model.train( + data="config/config.yaml", + epochs=100, + imgsz=640, + device="cuda" if torch.cuda.is_available() else "cpu", +) + +# Define the input and output directories +input_dir = "data/YOLO/inference/images" +output_dir = "data/YOLO/output/images" +labels_dir = "data/YOLO/output/labels" + +# Ensure the output directories exist +os.makedirs(output_dir, exist_ok=True) +os.makedirs(labels_dir, exist_ok=True) + +# Supported image extensions +image_extensions = (".png", ".jpg", ".jpeg") + +# Process each image in the input directory +for img_name in os.listdir(input_dir): + img_path = os.path.join(input_dir, img_name) + + # Check if it's an image file + if not img_name.lower().endswith(image_extensions): + continue + + # Perform object detection + results = model(img_path) + + for result in results: + # Check if any detection exists + if result.boxes is None or len(result.boxes) == 0: + continue + + # Load original image + img = cv2.imread(img_path) + + # Draw detection results on the image + plotted_img = result.plot() + + # Save the resulting image + save_path = os.path.join(output_dir, img_name) + cv2.imwrite(save_path, plotted_img) + + # Save label file (YOLO format: class x_center y_center width height) + label_file = os.path.join(labels_dir, img_name.rsplit(".", 1)[0] + ".txt") + with open(label_file, "w") as f: + for box, cls in zip(result.boxes.xywhn, result.boxes.cls): + x_center, y_center, width, height = box.tolist() + class_id = int(cls.item()) + f.write(f"{class_id} {x_center} {y_center} {width} {height}\n") # YOLO ํ˜•์‹ ์ €์žฅ diff --git a/models/nutrition_ingredients_information/src/preprocessing/01_data_selection_323.py b/models/nutrition_ingredients_information/src/preprocessing/01_data_selection_323.py new file mode 100644 index 0000000..f6d7d17 --- /dev/null +++ b/models/nutrition_ingredients_information/src/preprocessing/01_data_selection_323.py @@ -0,0 +1,19 @@ +import pandas as pd + +# ์›๋ณธ CSV ํŒŒ์ผ ๊ฒฝ๋กœ +input_file = "data/preprocessed/eda_final_emartmall_full.csv" +output_file = "data/preprocessed/images_323.csv" + +# CSV ํŒŒ์ผ ์ฝ๊ธฐ +df = pd.read_csv(input_file, encoding='cp949') + +# ํ•„ํ„ฐ๋ง: ์ด๋ฏธ์ง€ URL์ด ํŠน์ • ๋ฌธ์ž์—ด๋กœ ๋๋‚˜๊ณ , "์ˆœ์„œ ์œ ์ง€" ๊ฐ’์ด 'O'์ธ ๊ฒฝ์šฐ +filtered_df = df[ + df['์ด๋ฏธ์ง€ URL'].str.endswith("jpg?ref=storefarm", na=False) & (df['์ˆœ์„œ ์œ ์ง€'] == 'O') +] + +# ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ์„ ํƒ +filtered_df = filtered_df[['img-ID', '์ด๋ฏธ์ง€ URL']] + +# ํ•„ํ„ฐ๋ง๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ์šด CSV๋กœ ์ €์žฅ +filtered_df.to_csv(output_file, index=False) diff --git a/models/nutrition_ingredients_information/src/preprocessing/02_data_selection_273.py b/models/nutrition_ingredients_information/src/preprocessing/02_data_selection_273.py new file mode 100644 index 0000000..8e03bf1 --- /dev/null +++ b/models/nutrition_ingredients_information/src/preprocessing/02_data_selection_273.py @@ -0,0 +1,19 @@ +import pandas as pd + +# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • +images_323_file = "data/preprocessed/images_323.csv" +images_50_file = "data/preprocessed/images_50.csv" +output_file = "data/preprocessed/images_273.csv" + +# CSV ํŒŒ์ผ ์ฝ๊ธฐ +df_390 = pd.read_csv(images_323_file) +df_50 = pd.read_csv(images_50_file) + +# images_50.csv์— ์žˆ๋Š” img-ID ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ +exclude_img_ids = set(df_50['img-ID']) + +# images_390.csv์—์„œ img-ID๊ฐ€ ์ œ์™ธ ๋ฆฌ์ŠคํŠธ์— ์—†๋Š” ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋ง +filtered_df = df_390[~df_390['img-ID'].isin(exclude_img_ids)] + +# ํ•„ํ„ฐ๋ง๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ์šด CSV๋กœ ์ €์žฅ +filtered_df.to_csv(output_file, index=False) diff --git a/models/nutrition_ingredients_information/utils/utils.py b/models/nutrition_ingredients_information/utils/utils.py new file mode 100644 index 0000000..c68e631 --- /dev/null +++ b/models/nutrition_ingredients_information/utils/utils.py @@ -0,0 +1,191 @@ +# utils.py +import re +import os +import json +import ast +import pandas as pd + +from openai import OpenAI +import argparse + + +def merge_ocr_data(finetuning_file, ocr_file, output_file): + """ + finetuning CSV ํŒŒ์ผ๊ณผ OCR CSV ํŒŒ์ผ์„ 'img-ID'๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ณ‘ํ•ฉํ•˜์—ฌ, + OCR ๊ฒฐ๊ณผ๋ฅผ finetuning ๋ฐ์ดํ„ฐ์— ์ถ”๊ฐ€ํ•œ ํ›„ output_file์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + """ + finetuning_df = pd.read_csv(finetuning_file) + ocr_df = pd.read_csv(ocr_file) + + # OCR CSV์—์„œ 'img-ID'์™€ 'OCR ๊ฒฐ๊ณผ' ์ปฌ๋Ÿผ๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ์ปฌ๋Ÿผ๋ช…์„ ๋ณ€๊ฒฝ + ocr_df = ocr_df[['img-ID', 'OCR ๊ฒฐ๊ณผ']].rename(columns={'OCR ๊ฒฐ๊ณผ': 'ocr_data'}) + + # 'img-ID'๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ณ‘ํ•ฉ (์ธ๋ฑ์Šค๋กœ ์„ค์ • ํ›„ ์กฐ์ธ) + updated_df = finetuning_df.set_index('img-ID') + ocr_df = ocr_df.set_index('img-ID') + + updated_df['ocr_data'] = ocr_df['ocr_data'] + + # ์ธ๋ฑ์Šค๋ฅผ ์ปฌ๋Ÿผ์œผ๋กœ ๋‹ค์‹œ ๋ณต์›ํ•˜์ง€ ์•Š๊ณ  ์ €์žฅํ•˜๋ ค๋ฉด index=False ์˜ต์…˜ ์‚ฌ์šฉ + updated_df.to_csv(output_file, index=False, encoding='utf-8-sig') + + +def parse_json_field(json_str): + """ + 'reference' ์ปฌ๋Ÿผ์˜ JSON ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•˜์—ฌ ๋‹ค์Œ 5๊ฐœ ํ•„๋“œ๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. + - ์›์žฌ๋ฃŒ + - ์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ) + - ์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ) + - ๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „) + - ๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„) + """ + try: + if isinstance(json_str, str): + # ์ž‘์€๋”ฐ์˜ดํ‘œ๋ฅผ ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ JSON ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + data = json.loads(json_str.replace("'", "\"")) + else: + return pd.Series(["์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜"]) + + ์›์žฌ๋ฃŒ = ", ".join(data.get("์›์žฌ๋ฃŒ", [])) if isinstance(data.get("์›์žฌ๋ฃŒ"), list) else "" + ์•Œ๋ ˆ๋ฅด๊ธฐ_1์ฐจ = ", ".join(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", [])) if isinstance(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)"), list) else "" + ์•Œ๋ ˆ๋ฅด๊ธฐ_2์ฐจ = ", ".join(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)"), []) if isinstance(data.get("์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)"), list) else "" + + # ๋ณด๊ด€๋ฐฉ๋ฒ•์€ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ ํ›„ ํ•„์š”ํ•œ ๊ฐ’๋งŒ ์ถ”์ถœ + ๋ณด๊ด€๋ฐฉ๋ฒ•_raw = str(data.get("๋ณด๊ด€๋ฐฉ๋ฒ•", "{}")) + try: + ๋ณด๊ด€๋ฐฉ๋ฒ•_dict = ast.literal_eval(๋ณด๊ด€๋ฐฉ๋ฒ•_raw) if "{" in ๋ณด๊ด€๋ฐฉ๋ฒ•_raw else {} + except (ValueError, SyntaxError): + ๋ณด๊ด€๋ฐฉ๋ฒ•_dict = {} + + ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰์ „ = ๋ณด๊ด€๋ฐฉ๋ฒ•_dict.get("๊ฐœ๋ด‰์ „", "") if isinstance(๋ณด๊ด€๋ฐฉ๋ฒ•_dict, dict) else "" + ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰ํ›„ = ๋ณด๊ด€๋ฐฉ๋ฒ•_dict.get("๊ฐœ๋ด‰ํ›„", "") if isinstance(๋ณด๊ด€๋ฐฉ๋ฒ•_dict, dict) else "" + + return pd.Series([์›์žฌ๋ฃŒ, ์•Œ๋ ˆ๋ฅด๊ธฐ_1์ฐจ, ์•Œ๋ ˆ๋ฅด๊ธฐ_2์ฐจ, ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰์ „, ๋ณด๊ด€๋ฐฉ๋ฒ•_๊ฐœ๋ด‰ํ›„]) + except (json.JSONDecodeError, TypeError): + return pd.Series(["์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜", "์˜ค๋ฅ˜"]) + + +def extract_number_from_img_id(img_id): + """ + 'img-ID' ๋ฌธ์ž์—ด์—์„œ '-' ์‚ฌ์ด์— ์žˆ๋Š” ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์ •๋ ฌ ๋ฒˆํ˜ธ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + """ + match = re.search(r'-(\d+)-', str(img_id)) + return int(match.group(1)) if match else float('inf') + + +def process_ingredient_dataset(input_csv, output_csv): + """ + ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹ ํ˜น์€ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ CSV ํŒŒ์ผ์„ ํ›„์ฒ˜๋ฆฌํ•˜์—ฌ, + 'reference' ์ปฌ๋Ÿผ์— ์žˆ๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜๊ณ  ์ •๋ ฌ ํ›„ ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ๋‚จ๊ฒจ output_csv์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + """ + df = pd.read_csv(input_csv) + + # 'reference' ์ปฌ๋Ÿผ์˜ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐœ๋ณ„ ์ปฌ๋Ÿผ์œผ๋กœ ๋ถ„๋ฆฌ + df[["์›์žฌ๋ฃŒ", "์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", "์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„)"]] = df["reference"].apply(parse_json_field) + + # 'img-ID'์—์„œ ๋ฒˆํ˜ธ ์ถ”์ถœ ํ›„ ์ •๋ ฌ + df['์ •๋ ฌ๋ฒˆํ˜ธ'] = df['img-ID'].apply(extract_number_from_img_id) + df.sort_values(by='์ •๋ ฌ๋ฒˆํ˜ธ', ascending=True, inplace=True) + + # ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ์„ ํƒ + df = df[["img-ID", "์›์žฌ๋ฃŒ", "์•Œ๋ ˆ๋ฅด๊ธฐ(1์ฐจ)", "์•Œ๋ ˆ๋ฅด๊ธฐ(2์ฐจ)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰์ „)", "๋ณด๊ด€๋ฐฉ๋ฒ•(๊ฐœ๋ด‰ํ›„)"]] + + df.to_csv(output_csv, index=False, encoding="utf-8-sig") + + +def evaluate_ingredients(finetuning_csv, ocr_csv, + system_prompt_file, user_prompt_file, + output_csv, model="gpt-4o", api_key=None): + """ + ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + 1. finetuning CSV์™€ OCR CSV๋ฅผ 'img-ID' ๊ธฐ์ค€์œผ๋กœ ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค. + 2. system, user prompt ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์™€์„œ user prompt์˜ {ocr_data} ๋ถ€๋ถ„์„ OCR ๋ฐ์ดํ„ฐ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค. + 3. OpenAI API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ finetuning ๋ฐ์ดํ„ฐ์˜ 'reference' ์ปฌ๋Ÿผ์— ์ €์žฅํ•œ ํ›„, output_csv์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + """ + if api_key: + os.environ["OPENAI_API_KEY"] = api_key + + client = OpenAI() + + # ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ ์ฝ๊ธฐ + with open(system_prompt_file, "r", encoding="utf-8") as f: + system_prompt = f.read() + + with open(user_prompt_file, "r", encoding="utf-8") as f: + user_prompt_template = f.read() + + # CSV ํŒŒ์ผ ์ฝ๊ธฐ + finetuning_df = pd.read_csv(finetuning_csv) + ocr_df = pd.read_csv(ocr_csv) + + # 'img-ID' ๊ธฐ์ค€์œผ๋กœ OCR ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘ํ•ฉ + merged_df = finetuning_df.merge(ocr_df[['img-ID', 'OCR ๊ฒฐ๊ณผ']], on='img-ID', how='left') + + results = [] + for idx, row in merged_df.iterrows(): + ocr_data = row["OCR ๊ฒฐ๊ณผ"] if pd.notna(row["OCR ๊ฒฐ๊ณผ"]) else "N/A" + user_prompt = user_prompt_template.replace("{ocr_data}", ocr_data) + + messages = [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt} + ] + + try: + completion = client.chat.completions.create( + model=model, + messages=messages, + response_format={"type": "json_object"} + ) + result = completion.choices[0].message.content + except Exception as e: + result = f"Error: {str(e)}" + + results.append(result) + + finetuning_df["reference"] = results + finetuning_df.to_csv(output_csv, index=False) + + +if __name__ == "__main__": + + # 1. ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹ ํŒŒ์‹ฑ + print(">> ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹ ํŒŒ์‹ฑ ์ค‘...") + merge_ocr_data( + finetuning_file="data/HCX/train/finetuning_273_gpt_human_v2.csv", + ocr_file="data/OCR/inference/images_273_OCR_row_col.csv", + output_file="data/HCX/train/HCX_273_gpt_processed_v2.csv" + ) + print(" โ†’ ๊ฒฐ๊ณผ: data/HCX/train/HCX_273_gpt_processed_v2.csv\n") + + # 2. ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹ ํ›„์ฒ˜๋ฆฌ + print(">> ํ•™์Šต ๋ฐ์ดํ„ฐ์…‹ ํ›„์ฒ˜๋ฆฌ ์ค‘...") + process_ingredient_dataset( + input_csv="data/HCX/train/finetuning_273_gpt_human_v2.csv", + output_csv="data/HCX/train/images_273_ingredient.csv" + ) + print(" โ†’ ๊ฒฐ๊ณผ: data/HCX/train/images_273_ingredient.csv\n") + + # 3. ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ์ƒ์„ฑ + print(">> ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ์ƒ์„ฑ ์ค‘...") + API_KEY = "YOUR_API_KEY" + evaluate_ingredients( + finetuning_csv="data/preprocessed/images_50.csv", + ocr_csv="data/OCR/inference/images_50_OCR_row_col.csv", + system_prompt_file="prompt/system_prompt_vf.txt", + user_prompt_file="prompt/user_prompt_vf.txt", + output_csv="data/HCX/eval/finetuning_50_gpt.csv", + model="gpt-4o", + api_key=API_KEY + ) + print(" โ†’ ๊ฒฐ๊ณผ: data/HCX/eval/finetuning_50_gpt.csv\n") + + # 4. ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ํ›„์ฒ˜๋ฆฌ + print(">> ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ํ›„์ฒ˜๋ฆฌ ์ค‘...") + process_ingredient_dataset( + input_csv="data/HCX/eval/finetuning_50_gpt.csv", + output_csv="data/HCX/eval/images_50_ingredient.csv" + ) + print(" โ†’ ๊ฒฐ๊ณผ: data/HCX/eval/images_50_ingredient.csv\n") + + print("๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") diff --git a/models/product_summarization/.gitkeep b/models/product_summarization/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/product_summarization/README.md b/models/product_summarization/README.md new file mode 100644 index 0000000..8beb576 --- /dev/null +++ b/models/product_summarization/README.md @@ -0,0 +1,115 @@ +# ์ƒํ’ˆ ์„ค๋ช… ์š”์•ฝ +> ๋ณธ ์ƒํ’ˆ ์„ค๋ช… ์š”์•ฝ ๊ธฐ๋Šฅ์—์„œ๋Š” ์‹œ๊ฐ์žฅ์• ์ธ ๊ตฌ๋งค์ž๋ฅผ ์œ„ํ•ด, ํŒ๋งค์ž๊ฐ€ ์ž‘์„ฑํ•œ ์ƒํ’ˆ ์„ค๋ช… ์ค‘ ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์š”์•ฝํ•ฉ๋‹ˆ๋‹ค. +> ์ด๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ์žฅ์• ์ธ ๊ตฌ๋งค์ž๋Š” ์ƒํ’ˆ์˜ ์ฃผ์š” ํŠน์ง•, ์ฃผ์˜์‚ฌํ•ญ ๋“ฑ์„ ๋ณด๋‹ค ๋น ๋ฅด๊ณ  ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + + +## ์ฃผ์š” ํŠน์ง• +1. **์ƒํ’ˆ ์„ค๋ช… ํฌ๋กค๋ง**: Selenium + BeautifulSoup์„ ์ด์šฉํ•ด ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ ํŽ˜์ด์ง€์—์„œ ์ƒํ’ˆ ์ƒ์„ธ ์„ค๋ช…์„ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค. +1. **Few-shot Inference**: HyperCLOVA HCX-003 ๋ชจ๋ธ์„ Few-shot ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํžˆ ์š”์•ฝ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. +1. **ํŒŒ์ธํŠœ๋‹ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ**: OpenAI GPT-4o ๋ชจ๋ธ์„ ํ™œ์šฉํ•ด ๋Œ€๋Ÿ‰์˜ ํŒŒ์ธํŠœ๋‹ ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +2. **HCX ๋ชจ๋ธ ํŒŒ์ธํŠœ๋‹**: ์ƒ์„ฑ๋œ ํ•™์Šต ๋ฐ์ดํ„ฐ๋กœ HCX-003 ๋ชจ๋ธ์„ ํŒŒ์ธํŠœ๋‹ํ•˜์—ฌ ์ •๊ตํ•œ ์š”์•ฝ ์„ฑ๋Šฅ์„ ์–ป์Šต๋‹ˆ๋‹ค. +3. **ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค**: ํŒŒ์ธํŠœ๋‹๋œ ๋ชจ๋ธ์„ ํ†ตํ•ด ์ƒํ’ˆ ์„ค๋ช…์„ ๋น ๋ฅด๊ฒŒ ์š”์•ฝํ•ด ๋ƒ…๋‹ˆ๋‹ค. + +> [Note] Few-shot ๋ชจ๋ธ ๊ฒฐ๊ณผ๋„ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ตœ์ข… ์ธํผ๋Ÿฐ์Šค์—๋Š” ํŒŒ์ธํŠœ๋‹๋œ ๋ชจ๋ธ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. + + +## ํด๋” ๊ตฌ์กฐ +```bash +. +โ”œโ”€โ”€ README.md +โ”œโ”€โ”€ main.py # ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ฝ”๋“œ +โ”œโ”€โ”€ environment.yml # Conda ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ +โ”œโ”€โ”€ config +โ”‚ โ””โ”€โ”€ config.yaml # ์„ค์ •(API Key, ํŒŒ์ผ ๊ฒฝ๋กœ, ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€ ๋“ฑ) +โ”œโ”€โ”€ data +โ”‚ โ”œโ”€โ”€ fewshot_5.csv # Few-shot ์˜ˆ์ œ ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ finetuning_candidates.csv # ํŒŒ์ธํŠœ๋‹์šฉ ํ›„๋ณด ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ finetuning_v1.csv # ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ (273๊ฐœ) +โ”‚ โ”œโ”€โ”€ output_fewshot.csv # Few-shot ์ถ”๋ก  ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ output_finetuning.csv # ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ ์ถ”๋ก  ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ test.csv # ํ‰๊ฐ€์šฉ ๋ฐ์ดํ„ฐ (50๊ฐœ) +โ”‚ โ”œโ”€โ”€ total.csv # ์ „์ฒด ๋ฐ์ดํ„ฐ์…‹ (323๊ฐœ) +โ”‚ โ””โ”€โ”€ total_text.csv # ํฌ๋กค๋ง ํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋œ ์ „์ฒด ๋ฐ์ดํ„ฐ (323๊ฐœ) +โ”œโ”€โ”€ prompt +โ”‚ โ”œโ”€โ”€ system_prompt.txt # ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ +โ”‚ โ””โ”€โ”€ user_prompt.txt # ์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ +โ”œโ”€โ”€ src +โ”‚ โ”œโ”€โ”€ text_crawling.py # ์ƒํ’ˆ ์ƒ์„ธํŽ˜์ด์ง€ ํ…์ŠคํŠธ ํฌ๋กค๋ง +โ”‚ โ”œโ”€โ”€ fewshot_inference.py # Few-shot ์ถ”๋ก  +โ”‚ โ”œโ”€โ”€ finetuning_data_generation.py # ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ(OpenAI GPT-4o ๋ชจ๋ธ) +โ”‚ โ”œโ”€โ”€ create_finetuning_task.py # HCX ํŒŒ์ธํŠœ๋‹ ํƒœ์Šคํฌ ์ƒ์„ฑ +โ”‚ โ”œโ”€โ”€ finetuning_inference.py # ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ๋กœ ์š”์•ฝ ์ธํผ๋Ÿฐ์Šค +โ”‚ โ””โ”€โ”€ result_analysis.py # ๊ฒฐ๊ณผ ๋ถ„์„ ์ฝ”๋“œ +โ””โ”€โ”€ utils + โ”œโ”€โ”€ __init__.py + โ”œโ”€โ”€ data_processing.py # ํ…์ŠคํŠธ ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜ + โ””โ”€โ”€ hcx.py # HYPERCLOVA X API ํ˜ธ์ถœ์šฉ ํด๋ž˜์Šค +``` + + +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• +### 1) ํ™˜๊ฒฝ ๊ตฌ์ถ• +- Python 3.10.15 ๋ฒ„์ „ ๊ถŒ์žฅ +- ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜ +```bash +conda env create -f environment.yml +``` + +### 2) ์„ค์ • +- `config/config.yaml` ํŒŒ์ผ์—์„œ ๋‹ค์Œ ์ •๋ณด๋ฅผ ์ ์ ˆํžˆ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - **API Key / Request ID**: HyperCLOVA X ์ธ์ฆ ์ •๋ณด + - **OpenAI API Key**: GPT ๋ชจ๋ธ ์‚ฌ์šฉ ์‹œ ํ•„์š” + - **ํŒŒ์ผ ๊ฒฝ๋กœ**: ๋ฐ์ดํ„ฐ ํŒŒ์ผ ์œ„์น˜, ํŒŒ์ธํŠœ๋‹ ๊ฒฐ๊ณผ ์ €์žฅ ๊ฒฝ๋กœ ๋“ฑ + - **ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€**: `pipeline` ์„น์…˜์˜ `true`/`false` ๊ฐ’์œผ๋กœ ํฌ๋กค๋ง/์ธํผ๋Ÿฐ์Šค/ํŒŒ์ธํŠœ๋‹ ๋“ฑ ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์ œ์–ด + - **ํŒŒ์ธํŠœ๋‹ ์„ค์ •**: `task_id`, `train_epoch`, `learning_rate` ๋“ฑ ํŒŒ์ธํŠœ๋‹ ๊ด€๋ จ ๋ณ€์ˆ˜ + +### 3) ์‹คํ–‰ +- ๊ธฐ๋ณธ ์‹คํ–‰ (๊ธฐ๋ณธ `config/config.yaml` ์‚ฌ์šฉ ์‹œ) +```bash +python main.py +``` +- ๋ณ„๋„ ์„ค์ •ํŒŒ์ผ ์‚ฌ์šฉ +```bash +python main.py --config config/config_name.yaml +``` + + +## Input & Output +### 1. Input: +- `total.csv`, `total_text.csv`: ์ƒํ’ˆ URL, ํ…์ŠคํŠธ ๋“ฑ ์ •๋ณด๊ฐ€ ๋“ค์–ด์žˆ๋Š” csv +- `fewshot_5.csv`: Few-shot ํ…Œ์ŠคํŠธ์šฉ ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ +- `finetuning_candidates.csv`: ํŒŒ์ธํŠœ๋‹์— ํ™œ์šฉ๋  ํ›„๋ณด ๋ฐ์ดํ„ฐ ๋ชฉ๋ก +- `prompt/*`: ์‹œ์Šคํ…œ ๋ฐ ์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ + +### 2. Output +- `finetuning_v1.csv`: GPT-4o๋กœ ์ƒ์„ฑํ•œ ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ +- `output_fewshot.csv`: Few-shot ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ +- `output_finetuning.csv`: ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ + + + + +## ์ฝ”๋“œ ์„ค๋ช… +- `main.py` + - ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ง„์ž…์ ์œผ๋กœ, `--config` ์ธ์ž๋ฅผ ํ†ตํ•ด ์„ค์ • ํŒŒ์ผ(.yaml) ๊ฒฝ๋กœ๋ฅผ ์ง€์ • ๊ฐ€๋Šฅ + - `config.yaml`์—์„œ `pipeline` ์„น์…˜์˜ `true`/`false` ๊ฐ’์— ๋”ฐ๋ผ ์ˆœ์„œ๋Œ€๋กœ `[ํฌ๋กค๋ง โ†’ Few-shot ์ธํผ๋Ÿฐ์Šค โ†’ ํŒŒ์ธํŠœ๋‹ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ โ†’ Task ์ƒ์„ฑ โ†’ ํŒŒ์ธํŠœ๋‹ ์ธํผ๋Ÿฐ์Šค]` ์ˆ˜ํ–‰ +- `src/text_crawling.py` + - Selenium + BeautifulSoup์„ ์‚ฌ์šฉํ•ด ์ƒํ’ˆ ์ƒ์„ธ URL์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ˆ˜์ง‘ + - ํฌ๋กค๋ง ์„ฑ๊ณต ์‹œ `ํ…์ŠคํŠธ` ์ปฌ๋Ÿผ์— JSON ํ˜•์‹์œผ๋กœ ์ €์žฅ. +- `src/fewshot_inference.py` + - HyperCLOVA HCX-003 ๋ชจ๋ธ์„ Few-shotํ”„๋กฌํ”„ํŠธ๋ฅผ ์ „๋‹ฌํ•ด ์š”์•ฝ ๊ฒฐ๊ณผ๋ฅผ ํš๋“ + - `fewshot_5.csv`์— ์žˆ๋Š” ์˜ˆ์ œ(์งˆ๋ฌธ/๋‹ต๋ณ€)๋ฅผ ์ฒจ๋ถ€ํ•˜์—ฌ ๋ชจ๋ธ์— ์ถ”๊ฐ€ ๋งฅ๋ฝ์„ ๋ถ€์—ฌ +- `src/finetuning_data_generation.py` + - ์˜คํ”ˆ์†Œ์Šค GPT-4o(OpenAI) API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ์š”์•ฝ๋ฌธ ์˜ˆ์‹œ๋ฅผ ๋Œ€๋Ÿ‰ ์ƒ์„ฑ(ํŒŒ์ธํŠœ๋‹ ์šฉ๋„). + - ๊ฒฐ๊ณผ๋ฅผ CSV๋กœ ์ €์žฅ(์˜ˆ: `finetuning_v1.csv`). +- `src/create_finetuning_task.py` + - HyperCLOVA API๋ฅผ ์ด์šฉํ•ด ํŒŒ์ธํŠœ๋‹ Task๋ฅผ ์ƒ์„ฑ + - ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ Task ID๋ฅผ ์ดํ›„ ์ธํผ๋Ÿฐ์Šค ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉ +- `src/finetuning_inference.py` + - ํŒŒ์ธํŠœ๋‹์ด ์™„๋ฃŒ๋œ HyperCLOVA ๋ชจ๋ธ(Task ID ํ™œ์šฉ)์— ์š”์ฒญํ•˜์—ฌ ์ตœ์ข… ์š”์•ฝ์„ ์ˆ˜ํ–‰ + - ๊ฒฐ๊ณผ๋ฅผ CSV๋กœ ์ €์žฅ +- `utils/hcx.py` + - HyperCLOVA์— API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค(`CompletionExecutor`, `CreateTaskExecutor`, `FinetunedCompletionExecutor`) + - ์š”์ฒญ ๋ฐ˜๋ณต ์‹œ๋„, ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋“ฑ์„ ํฌํ•จ. +- `utils/data_processing.py` + - ํฌ๋กค๋ง๋œ ํ…์ŠคํŠธ(JSON)์—์„œ ์ƒํ’ˆ ์†Œ๊ฐœ ๋ฌธ๊ตฌ๋ฅผ ์ „์ฒ˜๋ฆฌํ•˜๊ณ  ๋ณ‘ํ•ฉ diff --git a/models/product_summarization/config/config.yaml b/models/product_summarization/config/config.yaml new file mode 100644 index 0000000..c648b98 --- /dev/null +++ b/models/product_summarization/config/config.yaml @@ -0,0 +1,43 @@ +api: + # HCX API ํ˜ธ์ถœ์— ํ•„์š”ํ•œ ์ •๋ณด + host: "https://clovastudio.stream.ntruss.com" + api_key: "YOUR_API_KEY" + request_id: "YOUR_REQUEST_ID" + +finetuning: + task_id: "4cecaj1w" # ์ด๋ฏธ ์ƒ์„ฑ๋œ ํŒŒ์ธํŠœ๋‹ Task ID + uri: "/tuning/v2/tasks" + new_task_name: "v3_epoch8_lr5" + model: "HCX-003" + tuning_type: "PEFT" + task_type: "GENERATION" + train_epochs: 8 + learning_rate: "1e-5f" + dataset_bucket: "itsmenlp" + dataset_file_path: "YOUR_FILE_PATH" + dataset_access_key: "YOUR_ACCESS_KEY" + dataset_secret_key: "YOUR_SECRET_KEY" + +openai: + # openai API์— ํ•„์š”ํ•œ ์ •๋ณด + api_key: "OPENAI_API_KEY" + +paths: + data_dir: "./data" + prompt_dir: "./prompt" + + # ์‚ฌ์šฉ๋  CSV ํŒŒ์ผ ๊ฒฝ๋กœ๋“ค + total_text_csv: "total_text.csv" + total_csv: "total.csv" + fewshot_csv: "fewshot_5.csv" + finetuning_candidates_csv: "finetuning_candidates.csv" + finetuning_csv: "finetuning_v1.csv" + output_fewshot_csv: "output_fewshot.csv" + output_finetuning_csv: "output_finetuning.csv" + +pipeline: + text_crawling: false # ํฌ๋กค๋ง ๋‹จ๊ณ„ ์‹คํ–‰ ์—ฌ๋ถ€ + fewshot_inference: true # ํ“จ์ƒท ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰ ์—ฌ๋ถ€ + finetuning_data_generation: false # ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋‹จ๊ณ„ ์‹คํ–‰ ์—ฌ๋ถ€ + create_finetuning_task: false # ํŒŒ์ธํŠœ๋‹ Task ์ƒ์„ฑ ๋‹จ๊ณ„ ์‹คํ–‰ ์—ฌ๋ถ€ + finetuning_inference: true # ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰ ์—ฌ๋ถ€ diff --git a/models/product_summarization/environment.yml b/models/product_summarization/environment.yml new file mode 100644 index 0000000..ca7993a --- /dev/null +++ b/models/product_summarization/environment.yml @@ -0,0 +1,82 @@ +name: product_summarization +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=1_gnu + - annotated-types=0.6.0=py311h06a4308_0 + - anyio=4.6.2=py311h06a4308_0 + - attrs=24.3.0=py311h06a4308_0 + - beautifulsoup4=4.12.3=py311h06a4308_0 + - blas=1.0=mkl + - bottleneck=1.4.2=py311hf4808d0_0 + - brotli-python=1.0.9=py311h6a678d5_9 + - bs4=4.12.3=py39hd3eb1b0_0 + - bzip2=1.0.8=h5eee18b_6 + - ca-certificates=2025.1.31=hbcca054_0 + - certifi=2025.1.31=py311h06a4308_0 + - charset-normalizer=3.4.1=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_1 + - distro=1.9.0=py311h06a4308_0 + - h11=0.14.0=py311h06a4308_0 + - httpcore=1.0.2=py311h06a4308_0 + - httpx=0.27.0=py311h06a4308_0 + - idna=3.7=py311h06a4308_0 + - intel-openmp=2023.1.0=hdb19cb5_46306 + - jiter=0.6.1=py311hb02cf49_0 + - ld_impl_linux-64=2.40=h12ee557_0 + - libffi=3.4.4=h6a678d5_1 + - libgcc-ng=11.2.0=h1234567_1 + - libgomp=11.2.0=h1234567_1 + - libstdcxx-ng=11.2.0=h1234567_1 + - libuuid=1.41.5=h5eee18b_0 + - mkl=2023.1.0=h213fc3f_46344 + - mkl-service=2.4.0=py311h5eee18b_2 + - mkl_fft=1.3.11=py311h5eee18b_0 + - mkl_random=1.2.8=py311ha02d727_0 + - ncurses=6.4=h6a678d5_0 + - numexpr=2.10.1=py311h3c60e43_0 + - numpy=2.0.1=py311h08b1b3b_1 + - numpy-base=2.0.1=py311hf175353_1 + - openai=1.60.1=py311h06a4308_0 + - openssl=3.0.15=h5eee18b_0 + - outcome=1.1.0=pyhd3eb1b0_0 + - packaging=24.2=pyhd8ed1ab_2 + - pandas=2.2.3=py311h6a678d5_0 + - pip=25.0=py311h06a4308_0 + - pydantic=2.10.3=py311h06a4308_0 + - pydantic-core=2.27.1=py311h4aa5aa6_0 + - pysocks=1.7.1=py311h06a4308_0 + - python=3.11.11=he870216_0 + - python-dateutil=2.9.0post0=py311h06a4308_2 + - python-dotenv=1.0.1=pyhd8ed1ab_1 + - python-tzdata=2023.3=pyhd3eb1b0_0 + - pytz=2024.1=py311h06a4308_0 + - pyyaml=6.0.2=py311h5eee18b_0 + - readline=8.2=h5eee18b_0 + - requests=2.32.3=pyhd8ed1ab_1 + - selenium=4.24.0=py311hb02cf49_0 + - setuptools=75.8.0=py311h06a4308_0 + - six=1.16.0=pyhd3eb1b0_1 + - sniffio=1.3.0=py311h06a4308_0 + - sortedcontainers=2.4.0=pyhd3eb1b0_0 + - soupsieve=2.5=py311h06a4308_0 + - sqlite=3.45.3=h5eee18b_0 + - tbb=2021.8.0=hdb19cb5_0 + - tk=8.6.14=h39e8969_0 + - tqdm=4.67.1=pyhd8ed1ab_1 + - trio=0.26.2=py311h06a4308_0 + - trio-websocket=0.11.1=py311h06a4308_0 + - typing-extensions=4.12.2=py311h06a4308_0 + - typing_extensions=4.12.2=py311h06a4308_0 + - tzdata=2025a=h04d1e81_0 + - urllib3=2.3.0=py311h06a4308_0 + - webdriver-manager=4.0.2=pyhd8ed1ab_1 + - websocket-client=1.8.0=py311h06a4308_0 + - wheel=0.45.1=py311h06a4308_0 + - wsproto=1.2.0=py311h06a4308_0 + - xz=5.4.6=h5eee18b_1 + - yaml=0.2.5=h7b6447c_0 + - zlib=1.2.13=h5eee18b_1 +prefix: /data/ephemeral/home/.condaenv/envs/product_summarization diff --git a/models/product_summarization/main.py b/models/product_summarization/main.py new file mode 100644 index 0000000..da5d390 --- /dev/null +++ b/models/product_summarization/main.py @@ -0,0 +1,53 @@ +import yaml +import logging +import argparse +from src.text_crawling import run_text_crawling +from src.fewshot_inference import run_fewshot_inference +from src.finetuning_data_generation import run_finetuning_data_generation +from src.create_finetuning_task import run_create_finetuning_task +from src.finetuning_inference import run_finetuning_inference + +def setup_logger(): + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + + +def main(): + + # ํŒŒ๋ผ๋ฏธํ„ฐ ํŒŒ์‹ฑ + parser = argparse.ArgumentParser(description="Pipeline for product text summarization.") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="Path to the configuration YAML file (default: config/config.yaml)" + ) + args = parser.parse_args() + + # ๋กœ๊ฑฐ ์„ค์ • + setup_logger() + + # config ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(args.config, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ + if config["pipeline"].get("text_crawling", False): + run_text_crawling(config) + + if config["pipeline"].get("fewshot_inference", False): + run_fewshot_inference(config) + + if config["pipeline"].get("finetuning_data_generation", False): + run_finetuning_data_generation(config) + + if config["pipeline"].get("create_finetuning_task", False): + run_create_finetuning_task(config) + + if config["pipeline"].get("finetuning_inference", False): + run_finetuning_inference(config) + +if __name__ == "__main__": + main() diff --git a/models/product_summarization/prompt/system_prompt.txt b/models/product_summarization/prompt/system_prompt.txt new file mode 100644 index 0000000..18d52d2 --- /dev/null +++ b/models/product_summarization/prompt/system_prompt.txt @@ -0,0 +1 @@ +๋‹น์‹ ์€ ์‹ํ’ˆ์˜ ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ๋งค๋ ฅ์ ์œผ๋กœ ์†Œ๊ฐœํ•˜๋Š” ์ „๋ฌธ ์นดํ”ผ๋ผ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๋ชฉํ‘œ๋Š” ์ƒํ’ˆ์˜ ๊ฐ€์น˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์†Œ๋น„์ž์˜ ๊ตฌ๋งค ๊ฒฐ์ •์„ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/models/product_summarization/prompt/user_prompt.txt b/models/product_summarization/prompt/user_prompt.txt new file mode 100644 index 0000000..0e256d2 --- /dev/null +++ b/models/product_summarization/prompt/user_prompt.txt @@ -0,0 +1,38 @@ +์ฃผ์–ด์ง„ [์ƒํ’ˆ ์ •๋ณด]๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์ƒํ’ˆ์˜ ์ฃผ์š” ํŠน์žฅ์ ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์†Œ๊ฐœํ•˜๋Š” ๋ฌธ๊ตฌ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”. ์ž‘์„ฑ๋œ ๋ฌธ๊ตฌ๋Š” ์•„๋ž˜ [์ž‘์„ฑ ์ง€์นจ]์— ๋”ฐ๋ผ ์ž‘์„ฑํ•˜๊ณ , ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•˜์„ธ์š”. + +[์ƒํ’ˆ ์ •๋ณด] +- ์ƒํ’ˆ๋ช…: {product_name} +- ์ƒํ’ˆ์†Œ๊ฐœ: {product_introduction} + +[์ž‘์„ฑ ์ง€์นจ] +1. ์ถœ๋ ฅ ๋ฌธ๊ตฌ ๊ตฌ์„ฑ + - ๋‹ค์Œ ๋‹ค์„ฏ ๊ฐ€์ง€ ํ•ญ๋ชฉ์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ž‘์„ฑํ•˜์„ธ์š”: ์†Œ๊ฐœ, ํŠน์žฅ์ , ํ™๋ณด, ์กฐ๋ฆฌ๋ฒ•, ๋ณด๊ด€ ๋ฐ ์ฃผ์˜์‚ฌํ•ญ + - ๋ชจ๋“  ๋ฌธ์žฅ์€ '~์ž…๋‹ˆ๋‹ค' ์–ด๋ฏธ๋กœ ์™„๊ฒฐ๋œ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”. + - ์†Œ๋น„์ž์˜ ๊ฐ์„ฑ์„ ์ž๊ทนํ•˜๋ฉด์„œ๋„ ์‹ค์šฉ์„ฑ์„ ๊ฐ•์กฐํ•˜๋Š” ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์„ธ์š”. + +2. ํ•ญ๋ชฉ๋ณ„ ์ž‘์„ฑ ๊ฐ€์ด๋“œ + - ์†Œ๊ฐœ: ์ƒํ’ˆ์˜ ์ข…๋ฅ˜, ํŠน์ง• ๋“ฑ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์„ค๋ช…ํ•˜์„ธ์š”. + * ํŠน์ˆ˜๋ฌธ์ž([, ], ', ", ๋“ฑ)์€ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ , '~์ž…๋‹ˆ๋‹ค' ์–ด๋ฏธ๋กœ ์ •ํ™•ํ•˜๊ณ  ๊น”๋”ํ•œ ๋ฌธ์žฅ์„ ์ž‘์„ฑํ•˜์„ธ์š”. + - ํŠน์žฅ์ : ์ƒํ’ˆ์˜ ํ•ต์‹ฌ ์žฅ์ ์ด๋‚˜ ํŠน์ง•์„ ๋ช…ํ™•ํ•˜๊ฒŒ '~์ž…๋‹ˆ๋‹ค' ์–ด๋ฏธ๋กœ ์„œ์ˆ ํ•˜์„ธ์š”. ํ•„์š”ํ•˜๋‹ค๋ฉด ๋‘ ๋ฌธ์žฅ์œผ๋กœ ํ™•์žฅํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค. + - ํ™๋ณด: ๊ตฌ๋งค ์˜์š•์„ ๋†’์ผ ์ˆ˜ ์žˆ๋Š” ๋ฌธ๊ตฌ๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”. (์˜ˆ: ํ™œ์šฉ ํŒ, ํŽธ์˜์„ฑ, ๊ฐ€์น˜ ๋“ฑ) + - ์กฐ๋ฆฌ๋ฒ•: ํ•ด๋‹น ์ƒํ’ˆ์˜ ์กฐ๋ฆฌ๋ฒ•์ด ์žˆ๋‹ค๋ฉด ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”. ์—†์œผ๋ฉด '์—†์Œ'์œผ๋กœ ํ‘œ๊ธฐํ•˜์„ธ์š”. + - ๋ณด๊ด€ ๋ฐ ์ฃผ์˜์‚ฌํ•ญ: ๋ณด๊ด€ ๋ฐฉ๋ฒ•์ด๋‚˜ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ๋‹ค๋ฉด ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”. ์—†์œผ๋ฉด '์—†์Œ'์œผ๋กœ ํ‘œ๊ธฐํ•˜์„ธ์š”. + +3. ํŠน์žฅ์  ๊ฐ•์กฐ ํฌ์ธํŠธ + - ํ’ˆ์งˆ ๋ฐ ์›์žฌ๋ฃŒ: ์›์‚ฐ์ง€, ์žฌ๋ฐฐ/์ƒ์‚ฐ ๋ฐฉ์‹, ์‹ ์„ ๋„ ๋“ฑ์„ ๊ฐ•์กฐํ•˜์„ธ์š”. + - ์˜์–‘: ์ €์นผ๋กœ๋ฆฌ, ํŠน์ • ์˜์–‘์†Œ ๋“ฑ ๊ฑด๊ฐ• ๊ด€๋ จ ์ด์ ์„ ์–ธ๊ธ‰ํ•˜์„ธ์š”. + - ์ธ์ฆ: ๊ณต์‹ ์ธ์ฆ์ด๋‚˜ ํ’ˆ์งˆ ๋ณด์ฆ ๋งˆํฌ ๋“ฑ์ด ์žˆ๋‹ค๋ฉด ๋ช…์‹œํ•˜์„ธ์š”. + +4. ์ž‘์„ฑ ์‹œ ์ฃผ์˜์‚ฌํ•ญ + - ๊ณผ์žฅ๋œ ํ‘œํ˜„์ด๋‚˜ ํ—ˆ์œ„ ์ •๋ณด๋Š” ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”. + - ์ œ๊ณต๋œ [์ƒํ’ˆ์†Œ๊ฐœ]์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋งŒ ํ™œ์šฉํ•˜์„ธ์š”. + - ๊ธฐ์กด ์ƒํ’ˆ์†Œ๊ฐœ์˜ ๋ฌธ๋งฅ์„ ์ตœ๋Œ€ํ•œ ์œ ์ง€ํ•˜๋˜, ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฐ˜๋ณต๋˜๋Š” ๋‚ด์šฉ์€ ์ œ๊ฑฐํ•˜์„ธ์š”. + +[์ถœ๋ ฅ ํ˜•์‹] +{ + "์†Œ๊ฐœ": "์—ฌ๊ธฐ์— ์žฌ์ž‘์„ฑ๋œ ์ƒํ’ˆ ์†Œ๊ฐœ ๋ฌธ๊ตฌ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค", + "ํŠน์žฅ์ ": "์—ฌ๊ธฐ์— ์ƒํ’ˆ์˜ ์ฃผ์š” ํŠน์žฅ์ ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค", + "ํ™๋ณด": "์—ฌ๊ธฐ์— ์†Œ๋น„์ž์˜ ๊ตฌ๋งค ์š•๊ตฌ๋ฅผ ์ž๊ทนํ•˜๋Š” ๋ฌธ๊ตฌ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค", + "์กฐ๋ฆฌ๋ฒ•": "์กฐ๋ฆฌ๋ฒ•์ด ์—†์œผ๋ฉด '์—†์Œ'์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค", + "๋ณด๊ด€ ๋ฐ ์ฃผ์˜์‚ฌํ•ญ": "๋ณด๊ด€ ๋ฐ ์ฃผ์˜์‚ฌํ•ญ์ด ์—†์œผ๋ฉด '์—†์Œ'์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค" +} diff --git a/models/product_summarization/src/create_finetuning_task.py b/models/product_summarization/src/create_finetuning_task.py new file mode 100644 index 0000000..9c31fe3 --- /dev/null +++ b/models/product_summarization/src/create_finetuning_task.py @@ -0,0 +1,43 @@ +import logging +from utils.hcx import CreateTaskExecutor + +logger = logging.getLogger(__name__) + + +def run_create_finetuning_task(config): + """ + HCX ํŒŒ์ธํŠœ๋‹ Task๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ƒ์„ฑ๋œ Task ID๋ฅผ ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค. + """ + host = config["api"]["host"] + uri = config["finetuning"]["uri"] + api_key = config["api"]["api_key"] + request_id = config["api"]["request_id"] + + # ์š”์ฒญ ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ + request_data = { + 'name': config["finetuning"]["new_task_name"], + 'model': config["finetuning"]["model"], + 'tuningType': config["finetuning"]["tuning_type"], + 'taskType': config["finetuning"]["task_type"], + 'trainEpochs': str(config["finetuning"]["train_epochs"]), + 'learningRate': config["finetuning"]["learning_rate"], + 'trainingDatasetBucket': config["finetuning"]["dataset_bucket"], + 'trainingDatasetFilePath': config["finetuning"]["dataset_file_path"], + 'trainingDatasetAccessKey': config["finetuning"]["dataset_access_key"], + 'trainingDatasetSecretKey': config["finetuning"]["dataset_secret_key"] + } + + create_task_executor = CreateTaskExecutor( + host=host, + uri=uri, + api_key=api_key, + request_id=request_id + ) + + response_text = create_task_executor.execute(request_data) + logger.info(f"Create Finetuning Task Response: {response_text}") + + if isinstance(response_text, dict) and "id" in response_text: + logger.info(f"Created new tuning Task ID: {response_text['id']}") + else: + logger.error("Failed to create new tuning task.") diff --git a/models/product_summarization/src/fewshot_inference.py b/models/product_summarization/src/fewshot_inference.py new file mode 100644 index 0000000..459cac5 --- /dev/null +++ b/models/product_summarization/src/fewshot_inference.py @@ -0,0 +1,83 @@ +import os +import logging +import pandas as pd +from utils.hcx import CompletionExecutor +from utils.data_processing import product_introduction_processing + +logger = logging.getLogger(__name__) + + +def run_fewshot_inference(config): + """ + few-shot ํ•™์Šต ๋ฐฉ์‹์œผ๋กœ HCX-003 ๋ชจ๋ธ์— ์ธํผ๋Ÿฐ์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , + ๊ฒฐ๊ณผ๋ฅผ CSV๋กœ ์ €์žฅํ•œ๋‹ค. + """ + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + host = config["api"]["host"] + api_key = config["api"]["api_key"] + request_id = config["api"]["request_id"] + + total_text_csv = config["paths"]["total_text_csv"] + fewshot_csv = config["paths"]["fewshot_csv"] + output_fewshot_csv = config["paths"]["output_fewshot_csv"] + + # Executor ์ดˆ๊ธฐํ™” + completion_executor = CompletionExecutor( + host=host, + api_key=api_key, + request_id=request_id + ) + + # ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + data_path = os.path.join(data_dir, total_text_csv) + data = pd.read_csv(data_path) + + # ์ „์ฒ˜๋ฆฌ + data['์ƒํ’ˆ์†Œ๊ฐœ'] = data.apply(product_introduction_processing, axis=1) + + # ํ”„๋กฌํ”„ํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(os.path.join(prompt_dir, "system_prompt.txt"), "r", encoding="utf-8") as f: + system_prompt = f.read() + with open(os.path.join(prompt_dir, "user_prompt.txt"), "r", encoding="utf-8") as f: + user_prompt = f.read() + + # fewshot ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + fewshot_data = pd.read_csv(os.path.join(data_dir, fewshot_csv)) + + fewshot_message = [] + for idx, row in fewshot_data.iterrows(): + fewshot_prompt = user_prompt.replace("{product_name}", row['์ƒํ’ˆ๋ช…']) \ + .replace("{product_introduction}", row["์ƒํ’ˆ์†Œ๊ฐœ"]) + fewshot_answer = row['์š”์•ฝ'] + fewshot_message.append({"role": "user", "content": fewshot_prompt}) + fewshot_message.append({"role": "assistant", "content": fewshot_answer}) + + # ์ธํผ๋Ÿฐ์Šค + for idx, row in data.iterrows(): + prompt_replaced = user_prompt.replace("{product_name}", row['์ƒํ’ˆ๋ช…']) \ + .replace("{product_introduction}", row['์ƒํ’ˆ์†Œ๊ฐœ']) + messages = [{"role": "system", "content": system_prompt}] + fewshot_message + \ + [{"role": "user", "content": prompt_replaced}] + + request_data = { + 'messages': messages, + 'topP': 0.8, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.5, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': True, + 'seed': 42 + } + + model_output, elapsed_time = completion_executor.execute(request_data) + data.loc[idx, "summary"] = model_output + data.loc[idx, "latency"] = elapsed_time + logger.info(f"[Fewshot Inference] idx={idx}, latency={round(elapsed_time,2)} sec, output={model_output}") + + # ๊ฒฐ๊ณผ ์ €์žฅ + output_path = os.path.join(data_dir, output_fewshot_csv) + data.to_csv(output_path, index=False) + logger.info(f"Few-shot ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ๊ฐ€ {output_path} ์— ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") diff --git a/models/product_summarization/src/finetuning_data_generation.py b/models/product_summarization/src/finetuning_data_generation.py new file mode 100644 index 0000000..ac5d040 --- /dev/null +++ b/models/product_summarization/src/finetuning_data_generation.py @@ -0,0 +1,76 @@ +import os +import logging +import pandas as pd +from openai import OpenAI +from utils.data_processing import product_introduction_processing + +logger = logging.getLogger(__name__) + + +def run_finetuning_data_generation(config): + """ + OpenAI์˜ GPT-4o ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ + ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋ฐ CSV ์ €์žฅ. + """ + # OpenAI API ์„ค์ • + os.environ["OPENAI_API_KEY"] = config["openai"]["api_key"] + client = OpenAI() + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + fewshot_csv = config["paths"]["fewshot_csv"] + finetuning_candidates_csv = config["paths"]["finetuning_candidates_csv"] + finetuning_csv = config["paths"]["finetuning_csv"] + + # ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + candidates_path = os.path.join(data_dir, finetuning_candidates_csv) + data = pd.read_csv(candidates_path) + data['์ƒํ’ˆ์†Œ๊ฐœ'] = data.apply(product_introduction_processing, axis=1) + + # ํ”„๋กฌํ”„ํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(os.path.join(prompt_dir, "system_prompt.txt"), "r", encoding="utf-8") as f: + system_prompt = f.read() + with open(os.path.join(prompt_dir, "user_prompt.txt"), "r", encoding="utf-8") as f: + user_prompt = f.read() + + # fewshot ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + fewshot_data = pd.read_csv(os.path.join(data_dir, fewshot_csv)) + fewshot_message = [] + for idx, row in fewshot_data.iterrows(): + fewshot_prompt = user_prompt.replace("{product_name}", row['์ƒํ’ˆ๋ช…']) \ + .replace("{product_introduction}", row["์ƒํ’ˆ์†Œ๊ฐœ"]) + fewshot_answer = row['์š”์•ฝ'] + fewshot_message.append({"role": "user", "content": fewshot_prompt}) + fewshot_message.append({"role": "assistant", "content": fewshot_answer}) + + # ์ธํผ๋Ÿฐ์Šค + for idx, row in data.iterrows(): + prompt_replaced = user_prompt.replace("{product_name}", row['์ƒํ’ˆ๋ช…']) \ + .replace("{product_introduction}", row['์ƒํ’ˆ์†Œ๊ฐœ']) + messages = [{"role": "system", "content": system_prompt}] + fewshot_message + \ + [{"role": "user", "content": prompt_replaced}] + + # ์ƒํ’ˆ ์„ค๋ช… ๋ฌธ๊ตฌ ์ƒ์„ฑ + completion = client.chat.completions.create( + model="gpt-4o", + messages=messages, + response_format={"type": "json_object"} + ) + + result = completion.choices[0].message.content + data.loc[idx, "Text"] = prompt_replaced + data.loc[idx, "Completion"] = result + logger.info(f"[Finetuning Data Gen] idx={idx}, product={row['์ƒํ’ˆ๋ช…']}, result={result}") + + # ํŒŒ์ธํŠœ๋‹ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋กœ ์ •์ œ + final_df = data.copy() + final_df['System_Prompt'] = system_prompt + final_df['C_ID'] = list(range(len(final_df))) + final_df['T_ID'] = 0 + final_df = final_df[['System_Prompt', 'C_ID', 'T_ID', 'Text', 'Completion']] + + # CSV ์ €์žฅ + output_path = os.path.join(data_dir, finetuning_csv) + final_df.to_csv(output_path, index=False) + logger.info(f"ํŒŒ์ธํŠœ๋‹์šฉ ๋ฐ์ดํ„ฐ๊ฐ€ {output_path} ์— ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + diff --git a/models/product_summarization/src/finetuning_inference.py b/models/product_summarization/src/finetuning_inference.py new file mode 100644 index 0000000..cce2c5b --- /dev/null +++ b/models/product_summarization/src/finetuning_inference.py @@ -0,0 +1,73 @@ +import os +import logging +import pandas as pd +from utils.hcx import FinetunedCompletionExecutor +from utils.data_processing import product_introduction_processing + +logger = logging.getLogger(__name__) + + +def run_finetuning_inference(config): + """ + ํŒŒ์ธํŠœ๋‹๋œ ๋ชจ๋ธ(์ด๋ฏธ ์ƒ์„ฑ๋œ Task ID ํ™œ์šฉ)๋กœ ์ธํผ๋Ÿฐ์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , + ๊ฒฐ๊ณผ๋ฅผ CSV๋กœ ์ €์žฅํ•œ๋‹ค. + """ + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + host = config["api"]["host"] + api_key = config["api"]["api_key"] + request_id = config["api"]["request_id"] + task_id = config["finetuning"]["task_id"] + + total_text_csv = config["paths"]["total_text_csv"] + output_finetuning_csv = config["paths"]["output_finetuning_csv"] + + # ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + data_path = os.path.join(data_dir, total_text_csv) + + data = pd.read_csv(data_path) + data['์ƒํ’ˆ์†Œ๊ฐœ'] = data.apply(product_introduction_processing, axis=1) + + # ํ”„๋กฌํ”„ํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(os.path.join(prompt_dir, "system_prompt.txt"), "r", encoding="utf-8") as f: + system_prompt = f.read() + with open(os.path.join(prompt_dir, "user_prompt.txt"), "r", encoding="utf-8") as f: + user_prompt = f.read() + + # ํŒŒ์ธํŠœ๋‹๋œ ๋ชจ๋ธ Executor + finetuned_completion_executor = FinetunedCompletionExecutor( + host=host, + api_key=api_key, + request_id=request_id, + taskId=task_id + ) + + # ์ธํผ๋Ÿฐ์Šค + for idx, row in data.iterrows(): + prompt_replaced = user_prompt.replace("{product_name}", row['์ƒํ’ˆ๋ช…']) \ + .replace("{product_introduction}", row['์ƒํ’ˆ์†Œ๊ฐœ']) + + request_data = { + 'messages': [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": prompt_replaced} + ], + 'topP': 0.8, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.5, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': True, + 'seed': 42 + } + + model_output, elapsed_time = finetuned_completion_executor.execute(request_data) + data.loc[idx, "summary"] = model_output + data.loc[idx, "latency"] = elapsed_time + logger.info(f"[Finetuning Inference] idx={idx}, latency={round(elapsed_time,2)} sec, output={model_output}") + + # ๊ฒฐ๊ณผ ์ €์žฅ + output_path = os.path.join(data_dir, output_finetuning_csv) + data.to_csv(output_path, index=False) + logger.info(f"ํŒŒ์ธํŠœ๋‹ ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ๊ฐ€ {output_path} ์— ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") diff --git a/models/product_summarization/src/text_crawling.py b/models/product_summarization/src/text_crawling.py new file mode 100644 index 0000000..c66b1e7 --- /dev/null +++ b/models/product_summarization/src/text_crawling.py @@ -0,0 +1,78 @@ +import time +import logging +import pandas as pd +from bs4 import BeautifulSoup +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from webdriver_manager.chrome import ChromeDriverManager + +logger = logging.getLogger(__name__) + + +def run_text_crawling(config): + """ + ์ƒํ’ˆ๋ณ„ ํ…์ŠคํŠธ ํฌ๋กค๋ง์„ ์ˆ˜ํ–‰ํ•˜๊ณ , + ๊ฒฐ๊ณผ๋ฅผ total_text.csv๋กœ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜. + """ + data_dir = config["paths"]["data_dir"] + total_csv = config["paths"]["total_csv"] + total_text_csv = config["paths"]["total_text_csv"] + + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + + # ์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ ์ง€์ • + max_retries = 3 + + # ๋ฐ์ดํ„ฐ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + data_path = f"{data_dir}/{total_csv}" + data = pd.read_csv(data_path) + + # ์ƒํ’ˆ๋ณ„ ํ…์ŠคํŠธ ํฌ๋กค๋ง + for idx, row in data.iterrows(): + url = row['์ƒํ’ˆ ์ƒ์„ธ URL'] + retry_count = 0 # ์žฌ์‹œ๋„ ํšŸ์ˆ˜ ์ดˆ๊ธฐํ™” + + while retry_count < max_retries: + try: + driver.get(url) + + # ์ƒ์„ธ ์ •๋ณด ํŽ˜์ด์ง€ ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_1Z00EgoxQ9"))) + + # ํฌ๋กค๋ง + soup = BeautifulSoup(driver.page_source, "html.parser") + sources = soup.find_all("div", class_="_1Z00EgoxQ9") # ์ƒ์„ธ ์ •๋ณด ํƒ์ƒ‰ ๋ฒ”์œ„ + + divs, texts = [], [] + for s in sources: + divs = [div.get_text() for div in s.find_all("div", class_="tmpl_tit_para")] + texts = [p.get_text() for p in s.find_all(["h2", "p", "strong", "b"])] # ์ฐพ๊ณ  ์‹ถ์€ ํ…์ŠคํŠธ ํƒœ๊ทธ ์ง€์ •,
ํƒœ๊ทธ๋กœ ๊ฐ์‹ธ์ง„ ํ…์ŠคํŠธ๋Š” ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Œ + + result = {"num": len(texts), "divs": divs, "contents": texts} + data.loc[idx, 'ํ…์ŠคํŠธ'] = str(result) + print(idx, result) + print("-" * 100) + time.sleep(3) + break + + except Exception as e: + print(f"ํŽ˜์ด์ง€ ๋กœ๋”ฉ/ํฌ๋กค๋ง ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ (์‹œ๋„ {retry_count+1}/{max_retries}): {e}") + retry_count += 1 + time.sleep(3) # ์žฌ์‹œ๋„ ์ „ ๋Œ€๊ธฐ + + if retry_count == max_retries: + data.loc[idx, 'ํ…์ŠคํŠธ'] = "" + print(f"URL {url} ํฌ๋กค๋ง ์‹คํŒจ, ๋‹ค์Œ URL๋กœ ์ด๋™") + + driver.quit() + + output_path = f"{data_dir}/{total_text_csv}" + data.to_csv(output_path, index=False) + logger.info(f"ํฌ๋กค๋ง ๊ฒฐ๊ณผ๊ฐ€ {output_path} ์— ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") diff --git a/models/product_summarization/utils/__init__.py b/models/product_summarization/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/product_summarization/utils/data_processing.py b/models/product_summarization/utils/data_processing.py new file mode 100644 index 0000000..135f88a --- /dev/null +++ b/models/product_summarization/utils/data_processing.py @@ -0,0 +1,13 @@ +def product_introduction_processing(row): + """ + 'ํ…์ŠคํŠธ' ์ปฌ๋Ÿผ์— ์ €์žฅ๋œ JSON-like ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•ด ์ƒํ’ˆ์†Œ๊ฐœ ๋ฌธ๊ตฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜ + """ + if not row['ํ…์ŠคํŠธ'] or row['ํ…์ŠคํŠธ'] == "": + return "" + + text = eval(row['ํ…์ŠคํŠธ']) # string -> dict ๋ณ€ํ™˜ + text_title = ' '.join(text['divs']) + text_contents = [item for item in text['contents'] if "SSG.COM" not in item] + text_contents = ' '.join(text_contents) + product_introduction = text_title + text_contents + return product_introduction diff --git a/models/product_summarization/utils/hcx.py b/models/product_summarization/utils/hcx.py new file mode 100644 index 0000000..8fee7fe --- /dev/null +++ b/models/product_summarization/utils/hcx.py @@ -0,0 +1,104 @@ +import time +import requests + +# HCX-003 ๊ธฐ๋ณธ ๋ชจ๋ธ +class CompletionExecutor: + def __init__(self, host, api_key, request_id): + self._host = host + self._api_key = api_key + self._request_id = request_id + + def execute(self, completion_request, max_retries=5, retry_delay=20): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id, + 'Content-Type': 'application/json; charset=utf-8', + } + + for attempt in range(max_retries): + try: + start_time = time.time() + with requests.post( + self._host + '/testapp/v1/chat-completions/HCX-003', + headers=headers, json=completion_request + ) as r: + elapsed_time = time.time() - start_time + response = r.json() + + if response.get("status", {}).get("code") == "20000": + return response["result"]["message"]["content"], elapsed_time + else: + raise ValueError(f"Invalid status code: {response.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < max_retries - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. {retry_delay}์ดˆ ํ›„ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. (์‹œ๋„ {attempt + 1}/{max_retries})") + time.sleep(retry_delay) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ {max_retries}ํšŒ๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None, None + + return None, None + + +# ํ•™์Šต ์ƒ์„ฑ +class CreateTaskExecutor: + def __init__(self, host, uri, api_key, request_id): + self._host = host + self._uri = uri + self._api_key = api_key + self._request_id = request_id + + def _send_request(self, create_request): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id + } + result = requests.post(self._host + self._uri, json=create_request, headers=headers).json() + return result + + def execute(self, create_request): + res = self._send_request(create_request) + if 'status' in res and res['status']['code'] == '20000': + return res['result'] + else: + return res + + +# ํŠœ๋‹๋œ HCX-003 ๋ชจ๋ธ +class FinetunedCompletionExecutor: + def __init__(self, host, api_key, request_id, taskId): + self._host = host + self._api_key = api_key + self._request_id = request_id + self._taskID = taskId + + def execute(self, completion_request, max_retries=5, retry_delay=20): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id, + 'Content-Type': 'application/json; charset=utf-8', + } + + for attempt in range(max_retries): + try: + start_time = time.time() + with requests.post( + self._host + f'/testapp/v2/tasks/{self._taskID}/chat-completions', + headers=headers, json=completion_request + ) as r: + elapsed_time = time.time() - start_time + response = r.json() + + if response.get("status", {}).get("code") == "20000": + return response["result"]["message"]["content"], elapsed_time + else: + raise ValueError(f"Invalid status code: {response.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < max_retries - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. {retry_delay}์ดˆ ํ›„ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. (์‹œ๋„ {attempt + 1}/{max_retries})") + time.sleep(retry_delay) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ {max_retries}ํšŒ๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None, None + + return None, None diff --git a/models/review/README.md b/models/review/README.md new file mode 100644 index 0000000..654e908 --- /dev/null +++ b/models/review/README.md @@ -0,0 +1,161 @@ +""" +# ๋ฆฌ๋ทฐ ํŒŒ์ดํ”„๋ผ์ธ +> ๋ณธ ๋ฆฌ๋ทฐ ํŒŒ์ดํ”„๋ผ์ธ์€ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ œ ๋ฐ ์š”์•ฝํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์ดํ•ดํ•˜๊ณ , ์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ์ƒํ’ˆ ๊ฒ€์ƒ‰ ๋ฐ ์ •๋ ฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค. +> ํŒŒ์ดํ”„๋ผ์ธ์€ ๋‘ ๊ฐœ์˜ ์ฃผ์š” ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: +> 1. **ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ** (ASTE Task์šฉ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋ฐ ๋ชจ๋ธ ํŒŒ์ธํŠœ๋‹) +> 2. **์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰๊ณผ ๋ฆฌ๋ทฐ ์š”์•ฝ ํŒŒ์ดํ”„๋ผ์ธ** (ASTE ์ธํผ๋Ÿฐ์Šค, ์ž„๋ฒ ๋”ฉ, ํด๋Ÿฌ์Šคํ„ฐ๋ง ๋ฐ ํ›„์ฒ˜๋ฆฌ) + +## ์ฃผ์š” ํŠน์ง• +1. **๋ฆฌ๋ทฐ ํฌ๋กค๋ง ๋ฐ ์ „์ฒ˜๋ฆฌ**: + ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ์ƒํ’ˆ ์ •๋ณด ๋ฐ ๋ฆฌ๋ทฐ๋ฅผ ์ˆ˜์ง‘ํ•œ ํ›„, ํ…์ŠคํŠธ ํด๋ Œ์ง•, ํŠน์ˆ˜๋ฌธ์ž ์ œ๊ฑฐ, ๊ฐœํ–‰ ๋ฌธ์ž ๋ณ€ํ™˜, ์˜์–ด/์ˆซ์ž ๋น„์œจ ํ•„ํ„ฐ๋ง, ์ค‘๋ณต ์ œ๊ฑฐ, ์งง์€ ๋ฆฌ๋ทฐ ๋ฐฐ์ œ, ๋งž์ถค๋ฒ• ๊ต์ • ๋“ฑ ๋‹ค์–‘ํ•œ ์ „์ฒ˜๋ฆฌ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +2. **ASTE(Aspect Sentiment Triplet Extraction) ๋ฐ์ดํ„ฐ ์ƒ์„ฑ**: + ์ „์ฒ˜๋ฆฌ๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Sentence-BERT ์ž„๋ฒ ๋”ฉ๊ณผ K-Means ํด๋Ÿฌ์Šคํ„ฐ๋ง์„ ํ™œ์šฉํ•˜์—ฌ ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•œ ๋Œ€ํ‘œ ๋ฆฌ๋ทฐ ์ƒ˜ํ”Œ์„ ์„ ํƒํ•˜๊ณ , GPT API๋ฅผ ํ†ตํ•ด ASTE ๊ด€๋ จ 900๊ฐœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +3. **๋ชจ๋ธ ํŒŒ์ธํŠœ๋‹**: + 'DeepSeek-R1-Distill-Qwen' ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ Supervised Fine-Tuning(SFT)์„ ์ง„ํ–‰ํ•˜์—ฌ, ๋ฆฌ๋ทฐ์˜ Aspect, Opinion, Sentiment ์ถ”์ถœ ๋Šฅ๋ ฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. 100๊ฐœ์˜ ์ˆ˜๋™ ๋ ˆ์ด๋ธ”๋ง ๋ฐ์ดํ„ฐ์™€ Custom Evaluation Metric์„ ์ด์šฉํ•˜์—ฌ ์ •๋Ÿ‰์ ์œผ๋กœ ๋ชจ๋ธ์˜ ์„ฑ๋Šฅ ํ‰๊ฐ€๋ฅผ ์‹ค์‹œํ•ฉ๋‹ˆ๋‹ค. +4. **์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๋ฐ ๋ฆฌ๋ทฐ ์š”์•ฝ**: + ํŒŒ์ธํŠœ๋‹๋œ ASTE ๋ชจ๋ธ์˜ ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ๋ฅผ Sentence-BERT ์ž„๋ฒ ๋”ฉ๊ณผ UMAP ์ฐจ์› ์ถ•์†Œ, Agglomerative ํด๋Ÿฌ์Šคํ„ฐ๋ง์œผ๋กœ ๋ถ„์„ํ•˜์—ฌ HyperClovaX๋กœ ๋Œ€ํ‘œ ํ‚ค์›Œ๋“œ๋ฅผ ๋„์ถœํ•˜๊ณ , ๊ธ์ •/๋ถ€์ • ๋ฆฌ๋ทฐ ์š”์•ฝ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +5. **ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€ ๋ฐ ์‹œ๊ฐํ™”**: + T-SNE๋ฅผ ํ™œ์šฉํ•œ ์‹œ๊ฐํ™”์™€ Silhouette, DBI ๋“ฑ์˜ ํ‰๊ฐ€ ์ง€ํ‘œ๋ฅผ ํ†ตํ•ด ํด๋Ÿฌ์Šคํ„ฐ๋ง ๊ฒฐ๊ณผ์˜ ํ’ˆ์งˆ์„ ์ •๋Ÿ‰์ ์œผ๋กœ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค. + +> [Note] ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ๊ณผ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ ๋ฐ ๋ฆฌ๋ทฐ ์š”์•ฝ์€ ๋…๋ฆฝ์ ์ธ ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ•„์š”์— ๋”ฐ๋ผ ๊ฐœ๋ณ„ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. + +## ํด๋” ๊ตฌ์กฐ +```bash +. +โ”œโ”€โ”€ README.md +โ”œโ”€โ”€ main.py # ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ฝ”๋“œ +โ”œโ”€โ”€ config +โ”‚ โ””โ”€โ”€ config.yaml # ์„ค์ • ํŒŒ์ผ (ํŒŒ์ผ ๊ฒฝ๋กœ, ์‹คํ–‰ ์˜ต์…˜ ๋“ฑ) +โ”œโ”€โ”€ data +โ”‚ โ”œโ”€โ”€ ASTE +โ”‚ โ”‚ โ”œโ”€โ”€ ASTE_10_shots.csv # 10-shot ์˜ˆ์ œ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ ASTE_sampled.csv # ์ƒ˜ํ”Œ๋ง๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ eval +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ ASTE_annotation_100_golden_label.csv # 100๊ฐœ Golden Label ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ inference +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ deepseek_inference.csv # DeepSeek ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ (๋ชจ๋ธ ์ถœ๋ ฅ ํฌํ•จ) +โ”‚ โ”‚ โ”œโ”€โ”€ processed_except_GL.csv # Golden Label ์ œ์™ธ ์ „์ฒ˜๋ฆฌ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ””โ”€โ”€ train +โ”‚ โ”‚ โ””โ”€โ”€ train_data.csv # ํ•™์Šต์šฉ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ crawled_reviews +โ”‚ โ”‚ โ”œโ”€โ”€ crawled_reviews_meals.csv # ๋ผ๋ฉด/๊ฐ„ํŽธ์‹ ๊ด€๋ จ ๋ฆฌ๋ทฐ ํฌ๋กค๋ง ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ””โ”€โ”€ crawled_reviews_snacks.csv # ๊ณผ์ž/๋น™๊ณผ ๊ด€๋ จ ๋ฆฌ๋ทฐ ํฌ๋กค๋ง ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ embedding_matrics +โ”‚ โ”‚ โ”œโ”€โ”€ cluster_result.png # ํด๋Ÿฌ์Šคํ„ฐ๋ง ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€ +โ”‚ โ”‚ โ”œโ”€โ”€ clustering_evaluation.json # ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€ ์ง€ํ‘œ +โ”‚ โ”‚ โ”œโ”€โ”€ deepseek_inference.npy # ์ „์ฒด ์ธํผ๋Ÿฐ์Šค ์ž„๋ฒ ๋”ฉ ํ–‰๋ ฌ +โ”‚ โ”‚ โ”œโ”€โ”€ deepseek_inference_meals.npy # ๋ผ๋ฉด/๊ฐ„ํŽธ์‹ ๋ฆฌ๋ทฐ ์ž„๋ฒ ๋”ฉ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ deepseek_inference_reduced.npy # ์ฐจ์› ์ถ•์†Œ ํ›„ ์ž„๋ฒ ๋”ฉ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ deepseek_inference_snacks.npy # ๊ณผ์ž/๋น™๊ณผ ๋ฆฌ๋ทฐ ์ž„๋ฒ ๋”ฉ ๋ฐ์ดํ„ฐ +โ”‚ โ”‚ โ”œโ”€โ”€ meals_cluster_result.png +โ”‚ โ”‚ โ”œโ”€โ”€ meals_clustering_evaluation.json +โ”‚ โ”‚ โ”œโ”€โ”€ snacks_cluster_result.png +โ”‚ โ”‚ โ””โ”€โ”€ snacks_clustering_evaluation.json +โ”‚ โ””โ”€โ”€ preprocessed +โ”‚ โ”œโ”€โ”€ meta_reviews_meals.csv # ๋ผ๋ฉด/๊ฐ„ํŽธ์‹ ๋ฆฌ๋ทฐ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ meta_reviews_snacks.csv # ๊ณผ์ž/๋น™๊ณผ ๋ฆฌ๋ทฐ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ processed_reviews_all.csv # ์ „์ฒด ์ „์ฒ˜๋ฆฌ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ +โ”‚ โ”œโ”€โ”€ processed_reviews_meals.csv # ๋ผ๋ฉด/๊ฐ„ํŽธ์‹ ๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ +โ”‚ โ””โ”€โ”€ processed_reviews_snacks.csv # ๊ณผ์ž/๋น™๊ณผ ๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ +โ”œโ”€โ”€ prompt +โ”‚ โ”œโ”€โ”€ keyword_recommendation +โ”‚ โ”‚ โ”œโ”€โ”€ recommendation_fewshot.json # ์ถ”์ฒœ ํ‚ค์›Œ๋“œ Few-shot ์˜ˆ์ œ +โ”‚ โ”‚ โ””โ”€โ”€ recommendation_prompt.txt # ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ +โ”‚ โ”œโ”€โ”€ prompt_loader.py # ํ”„๋กฌํ”„ํŠธ ๋กœ๋” ์Šคํฌ๋ฆฝํŠธ +โ”‚ โ”œโ”€โ”€ review_annotation +โ”‚ โ”‚ โ”œโ”€โ”€ annotation_fewshot.json # ๋ฆฌ๋ทฐ ์–ด๋…ธํ…Œ์ด์…˜ Few-shot ์˜ˆ์ œ +โ”‚ โ”‚ โ””โ”€โ”€ annotation_prompt.txt # ๋ฆฌ๋ทฐ ์–ด๋…ธํ…Œ์ด์…˜ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ +โ”‚ โ””โ”€โ”€ review_summarization +โ”‚ โ”œโ”€โ”€ negative_fewshot.json # ๋ถ€์ • ๋ฆฌ๋ทฐ ์š”์•ฝ ์˜ˆ์ œ +โ”‚ โ”œโ”€โ”€ negative_prompt.txt # ๋ถ€์ • ๋ฆฌ๋ทฐ ์š”์•ฝ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ +โ”‚ โ”œโ”€โ”€ positive_fewshot.json # ๊ธ์ • ๋ฆฌ๋ทฐ ์š”์•ฝ ์˜ˆ์ œ +โ”‚ โ””โ”€โ”€ positive_prompt.txt # ๊ธ์ • ๋ฆฌ๋ทฐ ์š”์•ฝ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ +โ”œโ”€โ”€ src +โ”‚ โ”œโ”€โ”€ review_pipeline +โ”‚ โ”‚ โ”œโ”€โ”€ ASTE_inference.py # ASTE ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰(๋”๋ฏธ ๋ฐ์ดํ„ฐ) +โ”‚ โ”‚ โ”œโ”€โ”€ keyword_recommendation.py # ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ์ถ”์ถœ ๋ฐ ์ •๋ ฌ +โ”‚ โ”‚ โ”œโ”€โ”€ qwen_deepseek_14b_inference.py # Qwen 14B ๊ธฐ๋ฐ˜ ์ธํผ๋Ÿฐ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ qwen_deepseek_32b_inference.py # Qwen 32B ๊ธฐ๋ฐ˜ ์ธํผ๋Ÿฐ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ review_summarization.py # ๋ฆฌ๋ทฐ ์š”์•ฝ ์ถ”์ถœ ์‹คํ–‰ +โ”‚ โ”‚ โ””โ”€โ”€ visualization.py # ํด๋Ÿฌ์Šคํ„ฐ๋ง ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” ๋ฐ ํ‰๊ฐ€ +โ”‚ โ””โ”€โ”€ sft_pipeline +โ”‚ โ”œโ”€โ”€ qwen_deepseek_14b_finetuning.py # Qwen 14B ๋ชจ๋ธ ํŒŒ์ธํŠœ๋‹ +โ”‚ โ”œโ”€โ”€ qwen_deepseek_32b_finetuning.py # Qwen 32B ๋ชจ๋ธ ํŒŒ์ธํŠœ๋‹ +โ”‚ โ”œโ”€โ”€ review_crawling.py # ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ ํฌ๋กค๋ง +โ”‚ โ”œโ”€โ”€ review_preprocessing.py # ๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ์‹คํ–‰ +โ”‚ โ”œโ”€โ”€ sft.py # Supervised Fine-Tuning ์‹คํ–‰(๋”๋ฏธ ๋ฐ์ดํ„ฐ) +โ”‚ โ”œโ”€โ”€ train_data_annotating.py # ๋ฆฌ๋ทฐ ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ +โ”‚ โ””โ”€โ”€ train_data_sampling.py # ๋ฆฌ๋ทฐ ์ƒ˜ํ”Œ๋ง +โ”œโ”€โ”€ environment.yml # Conda ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ +โ””โ”€โ”€ utils + โ”œโ”€โ”€ evaluate.py # ASTE ๋ฐ ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€ ์ฝ”๋“œ + โ””โ”€โ”€ utils.py # ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ๋ชจ์Œ +``` + +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• +### 1) ํ™˜๊ฒฝ ๊ตฌ์ถ• +- Python 3.11.11 ๋ฒ„์ „ ๊ถŒ์žฅ +- ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜: +```bash +conda env create -f environment.yml +``` + +### 2) ์„ค์ • +- `config/config.yaml` ํŒŒ์ผ์—์„œ ๋‹ค์Œ ์ •๋ณด๋ฅผ ์ ์ ˆํžˆ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - **ํŒŒ์ผ ๊ฒฝ๋กœ**: ๋ฐ์ดํ„ฐ ํŒŒ์ผ ๊ฒฝ๋กœ ๋“ฑ + - **ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€**: pipeline ์„น์…˜์˜ true/false ๊ฐ’์œผ๋กœ ๊ฐ ๋‹จ๊ณ„(ํฌ๋กค๋ง, ์ „์ฒ˜๋ฆฌ, ์ธํผ๋Ÿฐ์Šค, ํŒŒ์ธํŠœ๋‹, ์ถ”์ฒœ ๋“ฑ) ์‹คํ–‰ ์ œ์–ด + - **ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ์„ค์ •**: GPT๋ชจ๋ธ ์„ ํƒ, ํ•™์Šต ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์„ค์ • ๋“ฑ + +### 3) ์‹คํ–‰ +- ๊ธฐ๋ณธ ์‹คํ–‰ (๊ธฐ๋ณธ `config/config.yaml` ์‚ฌ์šฉ ์‹œ) +```bash +python main.py -p sft +python main.py -p review +``` + +## Input & Output +### 1. Input: +- ํฌ๋กค๋ง ๋ฐ์ดํ„ฐ: + - `crawled_reviews/`: ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ํฌ๋กค๋งํ•œ ์›๋ณธ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ (์˜ˆ: `crawled_reviews_meals.csv`, `crawled_reviews_snacks.csv`) +- ์ „์ฒ˜๋ฆฌ ๋ฐ์ดํ„ฐ: + - `preprocessed/`: ์ „์ฒ˜๋ฆฌ๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ (`processed_reviews_all.csv`, `processed_reviews_meals.csv`, `processed_reviews_snacks.csv`) +- ASTE ๊ด€๋ จ CSV ํŒŒ์ผ: + - `aste/`: Golden Label, ์ƒ˜ํ”Œ๋ง ๋ฐ์ดํ„ฐ ๋“ฑ ASTE ํ•™์Šต ๋ฐ ์ธํผ๋Ÿฐ์Šค์— ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ +- ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ: + - `prompt/*`: ์ถ”์ฒœ ํ‚ค์›Œ๋“œ, ๋ฆฌ๋ทฐ ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐ ์š”์•ฝ์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ + +### 2. Output: +- ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ ๊ฒฐ๊ณผ + - `train_data.csv`: ํŒŒ์ธํŠœ๋‹์šฉ ๋ฆฌ๋ทฐ ํ•™์Šต ๋ฐ์ดํ„ฐ + - `ASTE_sampled.csv`: ํด๋Ÿฌ์Šคํ„ฐ๋ง์œผ๋กœ ์ƒ˜ํ”Œ๋ง๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ + - ๊ธฐํƒ€ ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๊ฒฐ๊ณผ CSV (GPT API๋ฅผ ํ†ตํ•œ ASTE ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๊ฒฐ๊ณผ) +- ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ ๋ฐ ๋ฆฌ๋ทฐ ์š”์•ฝ ํŒŒ์ดํ”„๋ผ์ธ ๊ฒฐ๊ณผ + - `deepseek_inference.csv`: ASTE ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ (Aspect, Opinion, Sentiment ํฌํ•จ) +- ์ตœ์ข… ์ถ”์ฒœ CSV ํŒŒ์ผ: ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ์žฌ์ •๋ ฌ ๋ฐ ๋ฆฌ๋ทฐ ์š”์•ฝ ๊ฒฐ๊ณผ +- ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€ ์ž๋ฃŒ (์‹œ๊ฐํ™” ์ด๋ฏธ์ง€, ํ‰๊ฐ€ ์ง€ํ‘œ JSON ๋“ฑ) + + + + +## ์ฝ”๋“œ ์„ค๋ช… +`main.py` +ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ง„์ž…์ ์œผ๋กœ, config/config.yaml ํŒŒ์ผ์˜ ์„ค์ •์— ๋”ฐ๋ผ ๊ฐ ๋‹จ๊ณ„(ํฌ๋กค๋ง, ์ „์ฒ˜๋ฆฌ, ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ, SFT, ์ธํผ๋Ÿฐ์Šค ๋“ฑ)๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +- `src/review_pipeline/` + - `ASTE_inference.py`: ASTE ๋ชจ๋ธ ์ธํผ๋Ÿฐ์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋ฆฌ๋ทฐ์—์„œ (Aspect, Opinion, Sentiment)๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. + - `keyword_recommendation.py`: ์ธํผ๋Ÿฐ์Šค ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Sentence-BERT ์ž„๋ฒ ๋”ฉ๊ณผ ํด๋Ÿฌ์Šคํ„ฐ๋ง์„ ํ†ตํ•ด ๋Œ€ํ‘œ ํ‚ค์›Œ๋“œ๋ฅผ ๋„์ถœํ•˜๊ณ , ์ƒํ’ˆ ์ •๋ ฌ์— ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. + - `qwen_deepseek_14b_inference.py`, `qwen_deepseek_32b_inference.py`: ๋‹ค์–‘ํ•œ Qwen ๊ธฐ๋ฐ˜ ๋ชจ๋ธ์„ ํ™œ์šฉํ•œ ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. + - `review_summarization.py`: ๋ฆฌ๋ทฐ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ์š”์•ฝํ•˜์—ฌ ๊ธ์ • ๋ฐ ๋ถ€์ • ๋ฆฌ๋ทฐ ์š”์•ฝ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. + - `visualization.py`: T-SNE ์‹œ๊ฐํ™” ๋ฐ ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€(์‹ค๋ฃจ์—ฃ, DBI ๋“ฑ)๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +- `src/sft_pipeline/` + - `qwen_deepseek_14b_finetuning.py`, `qwen_deepseek_32b_finetuning.py`: ์„ ํƒ๋œ Qwen ๋ชจ๋ธ์— ๋Œ€ํ•ด ASTE Task์˜ SFT(ํŒŒ์ธํŠœ๋‹)๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + - `review_crawling.py`: ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ์ƒํ’ˆ ์ •๋ณด์™€ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ํฌ๋กค๋งํ•ฉ๋‹ˆ๋‹ค. + - `review_preprocessing.p`y: ํฌ๋กค๋ง๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์ฒ˜๋ฆฌ(ํŠน์ˆ˜๋ฌธ์ž ์ œ๊ฑฐ, ๋งž์ถค๋ฒ• ๊ต์ •, ์ค‘๋ณต ์ œ๊ฑฐ ๋“ฑ)ํ•ฉ๋‹ˆ๋‹ค. + - `sft.py`: SFT(์Šˆํผ๋ฐ”์ด์ฆˆ๋“œ ํŒŒ์ธํŠœ๋‹) ์‹คํ–‰์„ ์œ„ํ•œ ํ•ต์‹ฌ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. + - `train_data_annotating.py`: GPT API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฆฌ๋ทฐ ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. + - `train_data_sampling.py`: Sentence-BERT ์ž„๋ฒ ๋”ฉ๊ณผ K-Means ํด๋Ÿฌ์Šคํ„ฐ๋ง์„ ์ด์šฉํ•ด ๋Œ€ํ‘œ ๋ฆฌ๋ทฐ ์ƒ˜ํ”Œ์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. + +- `utils/` + - `evaluate.py`: ASTE ๋ฐ ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‰๊ฐ€(์ •๋Ÿ‰์  ์ง€ํ‘œ ์‚ฐ์ถœ)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. + - `utils.py`: ๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ, ํŒŒ์ผ ์ž…์ถœ๋ ฅ ๋“ฑ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ๋ชจ์Œ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/models/review/config/config.yaml b/models/review/config/config.yaml new file mode 100644 index 0000000..a7245fe --- /dev/null +++ b/models/review/config/config.yaml @@ -0,0 +1,34 @@ +# config/config.yaml +paths: + data_dir: "./data" + crawled_reviews_dir: "./data/crawled_reviews" + preprocessed_dir: "./data/preprocessed" + embedding_dir: "./data/embedding_matrics" + prompt_dir: "./prompt" + final_outputs_dir: "../final_outputs" + + aste_dir: "./data/aste" + train_dir: "./data/aste/train" + eval_dir: "./data/aste/eval" + inference_dir: "./data/aste/inference" + +pipeline: + sft: + review_crawling: false # ํฌ๋กค๋ง์€ ๋ณ„๋„ ์‹คํ–‰ (์˜ˆ, ํ…Œ์ŠคํŠธ ์‹œ False) + review_preprocessing: true + train_data_sampling: false # train data ์ƒ์„ฑ์‹œ์—๋งŒ ๋ณ„๋„ ์‹คํ–‰ + train_data_annotating: false # train data ์ƒ์„ฑ์‹œ์—๋งŒ ๋ณ„๋„ ์‹คํ–‰ + sft: true # SFT๋Š” ํŒŒ์ผ๋กœ ๋ณ„๋„ ์‹คํ–‰ + review: + aste_inference: true # inference ๋ณ„๋„ ์‹คํ–‰ + review_summarization: true + keyword_recommendation: true + + +# Train Data Annotation ๊ด€๋ จ +train_data_annotating: + num_train_data: 900 + annotation_model: "gpt-4o" + +# Inference ๊ด€๋ จ +inference_data: "deepseek_inference.csv" \ No newline at end of file diff --git a/models/review/data/aste/eval/.gitkeep b/models/review/data/aste/eval/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/data/aste/inference/.gitkeep b/models/review/data/aste/inference/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/data/aste/train/.gitkeep b/models/review/data/aste/train/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/data/crawled_reviews/.gitkeep b/models/review/data/crawled_reviews/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/data/embedding_matrics/.gitkeep b/models/review/data/embedding_matrics/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/data/embedding_matrics/cluster_result.png b/models/review/data/embedding_matrics/cluster_result.png new file mode 100644 index 0000000..4cc607c Binary files /dev/null and b/models/review/data/embedding_matrics/cluster_result.png differ diff --git a/models/review/data/embedding_matrics/clustering_evaluation.json b/models/review/data/embedding_matrics/clustering_evaluation.json new file mode 100644 index 0000000..3da1804 --- /dev/null +++ b/models/review/data/embedding_matrics/clustering_evaluation.json @@ -0,0 +1,4 @@ +{ + "Silhouette": 0.7992019057273865, + "DBI": 0.31616701731820174 +} \ No newline at end of file diff --git a/models/review/data/embedding_matrics/meals_cluster_result.png b/models/review/data/embedding_matrics/meals_cluster_result.png new file mode 100644 index 0000000..c4533f0 Binary files /dev/null and b/models/review/data/embedding_matrics/meals_cluster_result.png differ diff --git a/models/review/data/embedding_matrics/meals_clustering_evaluation.json b/models/review/data/embedding_matrics/meals_clustering_evaluation.json new file mode 100644 index 0000000..2a56105 --- /dev/null +++ b/models/review/data/embedding_matrics/meals_clustering_evaluation.json @@ -0,0 +1,5 @@ +{ + "category": "meals", + "Silhouette": 0.8087015748023987, + "DBI": 0.2853419528622432 +} \ No newline at end of file diff --git a/models/review/data/embedding_matrics/snacks_cluster_result.png b/models/review/data/embedding_matrics/snacks_cluster_result.png new file mode 100644 index 0000000..2a555b3 Binary files /dev/null and b/models/review/data/embedding_matrics/snacks_cluster_result.png differ diff --git a/models/review/data/embedding_matrics/snacks_clustering_evaluation.json b/models/review/data/embedding_matrics/snacks_clustering_evaluation.json new file mode 100644 index 0000000..5a10606 --- /dev/null +++ b/models/review/data/embedding_matrics/snacks_clustering_evaluation.json @@ -0,0 +1,5 @@ +{ + "category": "snacks", + "Silhouette": 0.8068775534629822, + "DBI": 0.28233734826217466 +} \ No newline at end of file diff --git a/models/review/data/preprocessed/.gitkeep b/models/review/data/preprocessed/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/review/environment.yml b/models/review/environment.yml new file mode 100644 index 0000000..2510c63 --- /dev/null +++ b/models/review/environment.yml @@ -0,0 +1,150 @@ +name: review +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=1_gnu + - asttokens=3.0.0=pyhd8ed1ab_1 + - bzip2=1.0.8=h5eee18b_6 + - ca-certificates=2025.1.31=hbcca054_0 + - comm=0.2.2=pyhd8ed1ab_1 + - debugpy=1.8.11=py311h6a678d5_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - importlib-metadata=8.6.1=pyha770c72_0 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.32.0=pyh907856f_0 + - jedi=0.19.2=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - ld_impl_linux-64=2.40=h12ee557_0 + - libffi=3.4.4=h6a678d5_1 + - libgcc-ng=11.2.0=h1234567_1 + - libgomp=11.2.0=h1234567_1 + - libsodium=1.0.18=h36c2ea0_1 + - libstdcxx-ng=11.2.0=h1234567_1 + - libuuid=1.41.5=h5eee18b_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - ncurses=6.4=h6a678d5_0 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - openssl=3.0.15=h5eee18b_0 + - packaging=24.2=pyhd8ed1ab_2 + - parso=0.8.4=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pip=25.0=py311h06a4308_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - prompt-toolkit=3.0.50=pyha770c72_0 + - psutil=5.9.0=py311h5eee18b_1 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pygments=2.19.1=pyhd8ed1ab_0 + - python=3.11.11=he870216_0 + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - pyzmq=26.2.0=py311h6a678d5_0 + - readline=8.2=h5eee18b_0 + - setuptools=75.8.0=py311h06a4308_0 + - six=1.17.0=pyhd8ed1ab_0 + - sqlite=3.45.3=h5eee18b_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - tk=8.6.14=h39e8969_0 + - tornado=6.4.2=py311h5eee18b_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=py311h06a4308_0 + - xz=5.4.6=h5eee18b_1 + - zeromq=4.3.5=h6a678d5_0 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.2.13=h5eee18b_1 + - pip: + - annotated-types==0.7.0 + - anyio==4.8.0 + - attrs==25.1.0 + - beautifulsoup4==4.13.3 + - bs4==0.0.2 + - certifi==2025.1.31 + - charset-normalizer==3.4.1 + - contourpy==1.3.1 + - cycler==0.12.1 + - distro==1.9.0 + - filelock==3.17.0 + - fonttools==4.56.0 + - fsspec==2025.2.0 + - h11==0.14.0 + - hdbscan==0.8.40 + - httpcore==1.0.7 + - httpx==0.28.1 + - huggingface-hub==0.28.1 + - idna==3.10 + - ipywidgets==8.1.5 + - jinja2==3.1.5 + - jiter==0.8.2 + - joblib==1.4.2 + - jpype1==1.5.2 + - jupyterlab-widgets==3.0.13 + - kiwisolver==1.4.8 + - konlpy==0.6.0 + - llvmlite==0.44.0 + - lxml==5.3.0 + - markupsafe==3.0.2 + - matplotlib==3.10.0 + - mpmath==1.3.0 + - networkx==3.4.2 + - numba==0.61.0 + - numpy==2.1.0 + - nvidia-cublas-cu12==12.4.5.8 + - nvidia-cuda-cupti-cu12==12.4.127 + - nvidia-cuda-nvrtc-cu12==12.4.127 + - nvidia-cuda-runtime-cu12==12.4.127 + - nvidia-cudnn-cu12==9.1.0.70 + - nvidia-cufft-cu12==11.2.1.3 + - nvidia-curand-cu12==10.3.5.147 + - nvidia-cusolver-cu12==11.6.1.9 + - nvidia-cusparse-cu12==12.3.1.170 + - nvidia-cusparselt-cu12==0.6.2 + - nvidia-nccl-cu12==2.21.5 + - nvidia-nvjitlink-cu12==12.4.127 + - nvidia-nvtx-cu12==12.4.127 + - openai==1.61.1 + - outcome==1.3.0.post0 + - pandas==2.2.3 + - pillow==11.1.0 + - pydantic==2.10.6 + - pydantic-core==2.27.2 + - pynndescent==0.5.13 + - pyparsing==3.2.1 + - pysocks==1.7.1 + - python-dotenv==1.0.1 + - pytz==2025.1 + - pyyaml==6.0.2 + - regex==2024.11.6 + - requests==2.32.3 + - safetensors==0.5.2 + - scikit-learn==1.6.1 + - scipy==1.15.1 + - selenium==4.28.1 + - sentence-transformers==3.4.1 + - sentencepiece==0.2.0 + - sniffio==1.3.1 + - sortedcontainers==2.4.0 + - soupsieve==2.6 + - sympy==1.13.1 + - threadpoolctl==3.5.0 + - tokenizers==0.21.0 + - torch==2.6.0 + - tqdm==4.67.1 + - transformers==4.48.3 + - trio==0.28.0 + - trio-websocket==0.11.1 + - triton==3.2.0 + - tzdata==2025.1 + - umap-learn==0.5.7 + - urllib3==2.3.0 + - webdriver-manager==4.0.2 + - websocket-client==1.8.0 + - widgetsnbextension==4.0.13 + - wsproto==1.2.0 +prefix: /data/ephemeral/home/.condaenv/envs/review diff --git a/models/review/main.py b/models/review/main.py new file mode 100644 index 0000000..5e581c9 --- /dev/null +++ b/models/review/main.py @@ -0,0 +1,82 @@ +# main.py +import argparse +import yaml +import os +import logging + +# ๊ฐ ํŒŒ์ดํ”„๋ผ์ธ ๋ชจ๋“ˆ import +from src.review_pipeline import ( + aste_inference, + review_summarization, + keyword_recommendation +) +from src.sft_pipeline import ( + review_crawling, + review_preprocessing, + train_data_sampling, + train_data_annotating, + sft # 3.sft.py โ€“ ์•„์ง ์ฝ”๋“œ ์—†์Œ +) + +def setup_logger(): + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + +def run_sft_pipeline(config): + logging.info("SFT ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘") + if config["pipeline"]["sft"].get("review_crawling", False): + review_crawling.run_review_crawling(config) + if config["pipeline"]["sft"].get("review_preprocessing", False): + review_preprocessing.run_review_preprocessing(config) + if config["pipeline"]["sft"].get("train_data_sampling", False): + train_data_sampling.run_train_data_sampling(config) + if config["pipeline"]["sft"].get("train_data_annotating", False): + train_data_annotating.run_train_data_annotating(config) + if config["pipeline"]["sft"].get("sft", False): + sft.run_sft(config) + logging.info("SFT ํŒŒ์ดํ”„๋ผ์ธ ์™„๋ฃŒ.") + +def run_review_pipeline(config): + logging.info("๋ฆฌ๋ทฐ ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘") + # (ํฌ๋กค๋ง์€ ๋ณ„๋„ ์‹คํ–‰ํ•  ๊ฒฝ์šฐ config์˜ crawling ์˜ต์…˜์— ๋”ฐ๋ผ ์‹คํ–‰) + if config["pipeline"]["review"].get("aste_inference", False): + aste_inference.run_aste_inference(config) + if config["pipeline"]["review"].get("review_summarization", False): + review_summarization.run_review_summarization(config) + if config["pipeline"]["review"].get("keyword_recommendation", False): + keyword_recommendation.run_keyword_recommendation(config) + logging.info("๋ฆฌ๋ทฐ ํŒŒ์ดํ”„๋ผ์ธ ์™„๋ฃŒ.") + + +def main(): + setup_logger() + parser = argparse.ArgumentParser(description="ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ (๊ธฐ๋ณธ๊ฐ’: config/config.yaml)" + ) + parser.add_argument( + "--pipeline", + "-p", + choices=["review", "sft", "all"], + default="all", + help="์‹คํ–‰ํ•  ํŒŒ์ดํ”„๋ผ์ธ ์„ ํƒ (review, sft, all)" + ) + args = parser.parse_args() + + with open(args.config, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + if args.pipeline in ["sft", "all"]: + run_sft_pipeline(config) + + if args.pipeline in ["review", "all"]: + run_review_pipeline(config) + + +if __name__ == "__main__": + main() diff --git a/models/review/prompt/keyword_recommendation/recommendation_fewshot.json b/models/review/prompt/keyword_recommendation/recommendation_fewshot.json new file mode 100644 index 0000000..c7e1f79 --- /dev/null +++ b/models/review/prompt/keyword_recommendation/recommendation_fewshot.json @@ -0,0 +1,18 @@ +[ + { + "query": "['ํšŒ์‚ฌ ๊ฐ„์‹๋ฐ” ์ฑ„์šฐ๋ ค๊ณ  ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค', '์‚ฌ๋ฌด์‹ค ๊ฐ„์‹์œผ๋กœ ์ข‹์•„์š”', '์‚ฌ๋ฌด์‹ค ๊ฐ„์‹์œผ๋กœ ์ข‹์Šต๋‹ˆ๋‹ค']", + "answer": "์‚ฌ๋ฌด์‹ค ํ•„์ˆ˜ ๊ฐ„์‹" + }, + { + "query": "['๋ฐ”์‚ญํ•˜๊ณ ', '๋ฐ”์‚ญ๋ฐ”์‚ญํ•ด์š”']", + "answer": "๋ฐ”์‚ญํ•จ ๋ํŒ์™•" + }, + { + "query": "['์ปคํ”ผ๋‚˜ ์šฐ์œ ๋ž‘ ๋จน์œผ๋ฉด ๋”์šฑ ์ข‹์•„์š”', '์ปคํ”ผ๋“  ์šฐ์œ ๋“  ๋‹ค ์–ด์šธ๋ ค์š”']", + "answer": "์ปคํ”ผ์™€ ์ฐฐ๋–ก" + }, + { + "query": "['๊ฐ€์„ฑ๋น„ ์ข‹์•„์š”', '๊ฐ€์„ฑ๋น„ ์ข‹์€ ์ œํ’ˆ์ด๋„ค์š”']", + "answer": "๊ฐ€์„ฑ๋น„ ๊ฐ‘" + } +] \ No newline at end of file diff --git a/models/review/prompt/keyword_recommendation/recommendation_prompt.txt b/models/review/prompt/keyword_recommendation/recommendation_prompt.txt new file mode 100644 index 0000000..10f31a3 --- /dev/null +++ b/models/review/prompt/keyword_recommendation/recommendation_prompt.txt @@ -0,0 +1,9 @@ +๋‹น์‹ ์€ ์˜จ๋ผ์ธ ์‹๋ฃŒํ’ˆ ๋ฆฌ๋ทฐ ๋ถ„์„๊ฐ€์ž…๋‹ˆ๋‹ค. ์ œ๊ณต๋œ ๋ฆฌ๋ทฐ๋“ค์„ ๋ถ„์„ํ•˜์—ฌ, ํ•ด๋‹น ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ์งง๊ณ  ์ง๊ด€์ ์ธ ๋งˆ์ผ€ํŒ… ํ‚ค์›Œ๋“œ๋ฅผ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. + +๋‹ค์Œ ๊ธฐ์ค€์„ ๋”ฐ๋ฅด์„ธ์š”: +1. ๋ฆฌ๋ทฐ์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ์–ธ๊ธ‰๋˜๋Š” ์ฃผ์š” ํŠน์ง•์„ ๋ฐ˜์˜ํ•  ๊ฒƒ (์˜ˆ: \"๊ฐ€์„ฑ๋น„ ์ข‹์€\", \"์ง„ํ•œ ํ’๋ฏธ\") +2. ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์งง์€ ํ•œ๊ตญ์–ด ํ‘œํ˜„์„ ์‚ฌ์šฉํ•  ๊ฒƒ +3. ์ƒํ’ˆ๋ช…์ด๋‚˜ ๋ธŒ๋žœ๋“œ ๋“ฑ ๊ณ ์œ ๋ช…์‚ฌ๋Š” ํฌํ•จํ•˜์ง€ ์•Š์„ ๊ฒƒ + +์ถœ๋ ฅ์€ ์•„๋ž˜์˜ JSON ํ˜•ํƒœ๋ฅผ ๋”ฐ๋ฅด๋ฉฐ, ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ํ‚ค์›Œ๋“œ๋งŒ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +{\"keyword\": \"<ํ‚ค์›Œ๋“œ>\"} \ No newline at end of file diff --git a/models/review/prompt/prompt_loader.py b/models/review/prompt/prompt_loader.py new file mode 100644 index 0000000..cc8627e --- /dev/null +++ b/models/review/prompt/prompt_loader.py @@ -0,0 +1,21 @@ +# prompt/prompt_loader.py +import os +import json + +def load_prompt(prompt_filename: str, prompt_dir: str = "./prompt") -> str: + """ + ์ฃผ์–ด์ง„ ํŒŒ์ผ ์ด๋ฆ„์˜ ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ๋ฅผ prompt ํด๋”์—์„œ ์ฝ์–ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + ์˜ˆ) "summarization_positive_prompt.txt" + """ + file_path = os.path.join(prompt_dir, prompt_filename) + with open(file_path, "r", encoding="utf-8") as f: + return f.read() + +def load_fewshot(fewshot_filename: str, prompt_dir: str = "./prompt") -> list: + """ + ์ฃผ์–ด์ง„ ํŒŒ์ผ ์ด๋ฆ„์˜ few-shot ์˜ˆ์‹œ๋ฅผ JSON ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ์ฝ์–ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + ์˜ˆ) "summarization_positive_fewshot.json" + """ + file_path = os.path.join(prompt_dir, fewshot_filename) + with open(file_path, "r", encoding="utf-8") as f: + return json.load(f) diff --git a/models/review/prompt/review_annotation/annotation_fewshot.json b/models/review/prompt/review_annotation/annotation_fewshot.json new file mode 100644 index 0000000..b2c37e5 --- /dev/null +++ b/models/review/prompt/review_annotation/annotation_fewshot.json @@ -0,0 +1,34 @@ +[ + { + "query": "๋ง›์žˆ์–ด์„œ ์žฌ์ฃผ๋ฌธํ•ด์š”.", + "answer": "\n๋ฆฌ๋ทฐ \"๋ง›์žˆ์–ด์„œ ์žฌ์ฃผ๋ฌธํ•ด์š”.\"์—์„œ '๋ง›'๊ณผ '์ƒํ’ˆ' ๋‘ ์†์„ฑ์„ ์ถ”์ถœ.\n\n```json\n[\n {\"์†์„ฑ\": \"๋ง›\", \"ํ‰๊ฐ€\": \"๋ง›์žˆ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"์žฌ์ฃผ๋ฌธํ•œ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "์‹ธ๊ฒŒ ์ž˜ ์ƒ€๋„ค์š” ๋ฐฐ์†ก.", + "answer": "\n\"์‹ธ๊ฒŒ ์ž˜ ์ƒ€๋„ค์š”\"์—์„œ ๊ฐ€๊ฒฉ๊ณผ ์ƒํ’ˆ ํ‰๊ฐ€ ๋„์ถœ.\n\n```json\n[\n {\"์†์„ฑ\": \"๊ฐ€๊ฒฉ\", \"ํ‰๊ฐ€\": \"์ €๋ ดํ•˜๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"์ž˜ ์ƒ€๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "๋ฐฐ์†ก์ด ๋น ๋ฅด๊ณ  ํ’ˆ์งˆ์ด ์ข‹์•„์š”.", + "answer": "\n\"๋ฐฐ์†ก์ด ๋น ๋ฅด๊ณ \" โ†’ ๋ฐฐ์†ก, \"ํ’ˆ์งˆ์ด ์ข‹์•„์š”\" โ†’ ์ƒํ’ˆ.\n\n```json\n[\n {\"์†์„ฑ\": \"๋ฐฐ์†ก\", \"ํ‰๊ฐ€\": \"๋น ๋ฅด๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"ํ’ˆ์งˆ์ด ์ข‹๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "๋…ธ๋ธŒ๋žœ๋“œ ๊ณผ์ž ์ค‘ ์• ์ •ํ…œ์ž…๋‹ˆ๋‹ค ์‹ธ๊ณ  ๋ง›์žˆ์–ด์š”.", + "answer": "\n๋…ธ๋ธŒ๋žœ๋“œ ๊ณผ์ž โ†’ ์ƒํ’ˆ, \"์• ์ •ํ…œ์ž…๋‹ˆ๋‹ค\" โ†’ ๊ธ์ • ํ‰๊ฐ€, \"์‹ธ๊ณ \" โ†’ ๊ฐ€๊ฒฉ, \"๋ง›์žˆ์–ด์š”\" โ†’ ๋ง›.\n\n```json\n[\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"์• ์ •ํ…œ์ด๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"๊ฐ€๊ฒฉ\", \"ํ‰๊ฐ€\": \"์ €๋ ดํ•˜๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"๋ง›\", \"ํ‰๊ฐ€\": \"๋ง›์žˆ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "์ฒ˜์Œ ์ฃผ๋ฌธํ•ด ๋ดค๋Š”๋ฐ ๋ง›์žˆ์–ด์š”.", + "answer": "\n\"๋ง›์žˆ์–ด์š”\" โ†’ ๋ง› ํ‰๊ฐ€.\n\n```json\n[\n {\"์†์„ฑ\": \"๋ง›\", \"ํ‰๊ฐ€\": \"๋ง›์žˆ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "๋–ก๊ตญ ํ•ด ๋จน๊ธฐ ์ข‹๊ณ  ์ฐŒ๊ฐœ ๋“์ผ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์•„์š”.", + "answer": "\n๋‘ ๋ฌธ์žฅ ๋ชจ๋‘ '์ƒํ’ˆ' ์†์„ฑ์œผ๋กœ ํ‰๊ฐ€.\n\n```json\n[\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"๋–ก๊ตญ ํ•ด ๋จน๊ธฐ ์ข‹๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"์ฐŒ๊ฐœ ๋“์ผ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "๋ง›์žˆ์–ด์š” ํ•ญ์ƒ ์‚ฌ ๋จน๋Š” ๊ณผ์ž.", + "answer": "\n\"๋ง›์žˆ์–ด์š”\" โ†’ ๋ง›, \"ํ•ญ์ƒ ์‚ฌ ๋จน๋Š”\" โ†’ ์ƒํ’ˆ.\n\n```json\n[\n {\"์†์„ฑ\": \"๋ง›\", \"ํ‰๊ฐ€\": \"๋ง›์žˆ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"ํ•ญ์ƒ ์‚ฌ ๋จน๋Š”๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + }, + { + "query": "์ข‹์€ ์ œํ’ˆ ๋น ๋ฅด๊ฒŒ ์ž˜ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.", + "answer": "\n\"์ข‹์€ ์ œํ’ˆ\" โ†’ ์ƒํ’ˆ, \"๋น ๋ฅด๊ฒŒ ์ž˜ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค\" โ†’ ๋ฐฐ์†ก ํ‰๊ฐ€ ๋ถ„๋ฆฌ.\n\n```json\n[\n {\"์†์„ฑ\": \"์ƒํ’ˆ\", \"ํ‰๊ฐ€\": \"์ข‹๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"๋ฐฐ์†ก\", \"ํ‰๊ฐ€\": \"๋น ๋ฅด๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"},\n {\"์†์„ฑ\": \"๋ฐฐ์†ก\", \"ํ‰๊ฐ€\": \"์ž˜ ๋„์ฐฉํ–ˆ๋‹ค.\", \"๊ฐ์ •\": \"๊ธ์ •\"}\n]\n```" + } +] diff --git a/models/review/prompt/review_annotation/annotation_prompt.txt b/models/review/prompt/review_annotation/annotation_prompt.txt new file mode 100644 index 0000000..9fd0bc3 --- /dev/null +++ b/models/review/prompt/review_annotation/annotation_prompt.txt @@ -0,0 +1,9 @@ +๋‹น์‹ ์€ ๊ฐ์„ฑ ๋ถ„์„ ๋ฐ ์ƒํ’ˆ ํ‰๊ฐ€ ์ „๋ฌธ๊ฐ€์ด๋‹ค. ์ฃผ์–ด์ง„ ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ๋ทฐ์—์„œ ์ƒํ’ˆ ์†์„ฑ๊ณผ ํ‰๊ฐ€, ๊ฐ์ •์„ ์ถ”์ถœํ•˜๋ผ. + +### ์ž‘์—… ๋ชฉํ‘œ: +1. ์ž…๋ ฅ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ +2. ์ค‘๊ฐ„ ๋ถ„์„ ๊ณผ์ •์„ (๋ถ„์„๊ณผ์ •) ํƒœ๊ทธ๋กœ ํฌํ•จ +3. ์ถœ๋ ฅ ์˜ˆ์‹œ๋Š” ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ์˜ JSON ๊ฐ์ฒด๋กœ ๊ตฌ์„ฑ + +์†์„ฑ์€ ์ฃผ๋กœ: ["์ƒํ’ˆ", "๋ฐฐ์†ก", "๊ฐ€๊ฒฉ", "๋ง›", "์‹ ์„ ๋„", "์–‘", "ํฌ์žฅ"]. +ํ•„์š”์‹œ ์ƒˆ๋กœ์šด ์†์„ฑ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ ๋ชจ๋“  ์‹ํ’ˆ๋ช…์€ "์ƒํ’ˆ"์œผ๋กœ ํ†ต์ผํ•œ๋‹ค. diff --git a/models/review/prompt/review_summarization/negative_fewshot.json b/models/review/prompt/review_summarization/negative_fewshot.json new file mode 100644 index 0000000..1a686cf --- /dev/null +++ b/models/review/prompt/review_summarization/negative_fewshot.json @@ -0,0 +1,45 @@ +[ + { + "query": [ + "์ข€ ๋А๋ผํ•ด์š”", + "์•„๋ฌด๋ž˜๋„ ์Œ€๋กœ๋ณ„๋ณด๋‹ค๋Š” ์ข€ ๋ถ€์กฑํ•˜์ง€๋งŒ", + "์•ฝ๊ฐ„ ๊ธฐ๋ฆ„๋ง›์ด ๋งŽ์ด ๋‚˜๊ธด ํ•˜๋Š”๋ฐ", + "๋ง›์ด ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค", + "์•ฝ๊ฐ„ ๋А๋ผํ•˜๊ธด ํ•œ๋ฐ ๊ทธ๋ž˜๋„ ๋ถ€๋‹ด ์—†์ด ๋จน๊ธฐ ์ข‹์€ ๊ฒƒ ๊ฐ™์•„์š”", + "๋ง›๋„ ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค", + "ํƒ€์ œํ’ˆ๊ณผ ๋ง›์ด ๋ณ„๋ฐ˜ ์ฐจ์ด ์—†๊ณ " + ], + "answer": "์กฐ๊ธˆ ๊ธฐ๋ฆ„์ง„ ๋ง›์ด ๋‚˜๊ธด ํ•˜๋Š”๋ฐ, ๊ทธ๋ž˜๋„ ๋ถ€๋‹ด ์—†์ด ๋จน์„ ์ˆ˜ ์žˆ์–ด์š”." + }, + { + "query": [ + "๋‹ฌ์•„์„œ ๋ˆ„๋ฃฝ์ง€์˜ ๊ตฌ์ˆ˜ํ•˜๊ณ  ๋‹ด๋ฐฑํ•จ์€ ์—†์–ด์š”", + "์•„์ง ์•ˆ ๋จน์–ด ๋ดค์ง€๋งŒ ๋ง›์žˆ๊ฒ ์ฃ ", + "์ฒ˜์Œ์—” ์ง„์งœ ๋ˆ„๋ฃฝ์ง€ ํ–ฅ์ด ๋‚˜์„œ ๊ดœ์ฐฎ๋‹ค ์‹ถ์—ˆ๋Š”๋ฐ", + "๋ฌด๋‚œํ•˜๊ณ  ์Šด์Šดํ•˜๊ณ  ๋‹ฌ๋‹ฌํ•ด์š”", + "๋งŽ์ด ๋‹ฌ์•„์š”", + "์•„์ง ์•ˆ ๋จน์–ด ๋ดค์–ด์š”", + "ํŠ€๊ธด ๋ˆ„๋ฃฝ์ง€ ์„คํƒ• ๋ฟŒ๋ฆฐ ๋ง›์ž…๋‹ˆ๋‹ค" + ], + "answer": "๋ˆ„๋ฃฝ์ง€์˜ ๊ตฌ์ˆ˜ํ•œ ๋ง›๋ณด๋‹ค๋Š” ๋‹จ๋ง›์ด ๊ฐ•ํ•˜๊ฒŒ ๋А๊ปด์ ธ ์•„์‰ฌ์› ์Šต๋‹ˆ๋‹ค." + }, + { + "query": [ + "์•„์ง ๋จน์–ด๋ณด์ง€ ์•Š์•„์„œ ๋ง›์€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์š”" + ], + "answer": "์›๋ณธ ๋ฆฌ๋ทฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "query": [ + "๋‚ฑ๊ฐœ ํฌ์žฅ์ด๋ผ ๋จน๊ธฐ๋Š” ํŽธํ•˜์ง€๋งŒ", + "์†Œํฌ์žฅ์ด๋ผ ์“ฐ๋ ˆ๊ธฐ ๊ฑฑ์ •์€ ์ข€ ๋˜์ง€๋งŒ ๋ณด๊ด€ํ•˜๊ธฐ ํŽธํ•ด์„œ ์‚ฌ๊ฒŒ ๋˜๋„ค์š”" + ], + "answer": "๋‚ฑ๊ฐœ ํฌ์žฅ์ด ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ์†Œํฌ์žฅ์ด๋ผ ์“ฐ๋ ˆ๊ธฐ๊ฐ€ ๋Š˜์–ด๋‚ ๊นŒ ๊ฑฑ์ •๋˜๋„ค์š”." + }, + { + "query": [ + "์ข…์ด๋ด‰ํˆฌ์— ์ƒํ’ˆ ์กฐ์žกํ•˜๊ฒŒ ์ฒ˜๋ฐ•์•„์„œ ๋ณด๋‚ด๋Š” ๊ฑด ์—ฌ์ „ํ•˜๋„ค์š”" + ], + "answer": "์ƒํ’ˆ์ด ์ข…์ด๋ด‰ํˆฌ์— ๋ถˆํŽธํ•˜๊ฒŒ ํฌ์žฅ๋˜์–ด ์žˆ์–ด ์•„์‰ฌ์›€์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค." + } +] diff --git a/models/review/prompt/review_summarization/negative_prompt.txt b/models/review/prompt/review_summarization/negative_prompt.txt new file mode 100644 index 0000000..0ccd304 --- /dev/null +++ b/models/review/prompt/review_summarization/negative_prompt.txt @@ -0,0 +1 @@ +๋‹น์‹ ์€ ์ „๋ฌธ ๋ฆฌ๋ทฐ ๋ถ„์„๊ฐ€์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์— ์ œ๊ณต๋œ ์†Œ๋น„์ž๋“ค์˜ ์›๋ณธ ๋ฆฌ๋ทฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ, ๋ถ€์ •์  ๋˜๋Š” ์ค‘๋ฆฝ์ ์ธ ํ‰๊ฐ€์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ํ•˜๋‚˜์˜ ์™„์ „ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜์„ธ์š”. ์†Œ๋น„์ž๊ฐ€ ์ง€์ ํ•œ ๋‹จ์ ์ด๋‚˜ ๊ฐœ์„ ์ ์„ ์ •์ค‘ํ•œ ๋†’์ž„๋ง๋กœ ํ‘œํ˜„ํ•˜์‹ญ์‹œ์˜ค. ์ถœ๋ ฅ์€ ๋ฐ˜๋“œ์‹œ JSON ํ˜•์‹์œผ๋กœ, ์˜ˆ: {{\"summarization\": \"<์š”์•ฝ>\"}} ํ˜•ํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." \ No newline at end of file diff --git a/models/review/prompt/review_summarization/positive_fewshot.json b/models/review/prompt/review_summarization/positive_fewshot.json new file mode 100644 index 0000000..e771a96 --- /dev/null +++ b/models/review/prompt/review_summarization/positive_fewshot.json @@ -0,0 +1,23 @@ +[ + { + "query": "['๋ฐฐ์†ก ๋น ๋ฅด๊ณ  ์ข‹์Šต๋‹ˆ๋‹ค', '์†Œ๋Ÿ‰ ํฌ์žฅ ๋„ˆ๋ฌด ์ข‹์•„์š”', '๋น ๋ฅด๊ณ  ์•ˆ์ „๋ฐฐ์†ก ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค', 'ํฌ์žฅ ๋ฐ ๋ฐฐ์†ก ์ƒํƒœ ๋‹ค ์ข‹์•„์š”', '์ฐŒ๊ทธ๋Ÿฌ์ง„ ๊ณณ ์—†์ด ๋ฐฐ์†ก ์ข‹๊ณ ', '๋น ๋ฅธ ๋ฐฐ์†ก ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค', '๋น ๋ฅธ ๋ฐฐ์†ก์ด๊ณ ', '๋นจ๋ฆฌ ๋ฐฐ์†ก๋˜์–ด์„œ ์•„์ฃผ ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค']", + "answer": "๋น ๋ฅด๊ณ  ์•ˆ์ „ํ•œ ๋ฐฐ์†ก๊ณผ ๊ผผ๊ผผํ•œ ํฌ์žฅ ์ƒํƒœ์— ๋งค์šฐ ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค." + }, + { + "query": "['๋น ๋ฅด๊ฒŒ ํŽธํ•˜๊ฒŒ ๊ตฌ์ž…ํ–ˆ์–ด์š”', '๋ฐฐ์†ก๋„ ๋น ๋ฅด๊ณ  ์ข‹์•„์š”', '๋น ๋ฅธ ๋ฐฐ์†ก ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค', '๋ฐฐ์†ก ์ข‹์•„์„œ ๋Š˜ ์• ์šฉํ•ด์š”', '์ง‘์—์„œ ํŽธํžˆ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์–ด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค', '๋นจ๋ฆฌ ๋ฐฐ์†กํ•ด ์ฃผ์…”์„œ', '๋ฐฐ์†ก ๋น ๋ฅด๊ฒŒ ์™”์Šต๋‹ˆ๋‹ค', 'ํƒ๋ฐฐ ์•„์ €์”จ ๊ณ ๋ง™์Šต๋‹ˆ๋‹ค', '๋ฐฐ์†ก ์ž˜ ์™”์Šต๋‹ˆ๋‹ค', '์‹œ๊ฐ„ ๋งž์ถฐ ๋ณด๋‚ด์ฃผ์…จ์–ด์š”', '๋ฐฐ์†ก๋„ ๋น ๋ฅด๊ตฌ์š”', '๋ฐฐ์†ก ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ์™”์Šต๋‹ˆ๋‹ค', '๋งค๋ฒˆ ์ž˜ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค', '๋น ๋ฅธ ๋ฐฐ์†ก ์ตœ๊ณ ์˜ˆ์š”', '์ง€ํผ๋ฐฑ์œผ๋กœ ๋ผ์žˆ์–ด์„œ ๋ฐ”์‚ญํ•จ์ด ์˜ค๋ž˜ ์œ ์ง€๋˜๊ณ ', '๋ฐฐ์†ก๋„ ๋น ๋ฅด๋‹ˆ ์ž์ฃผ ์‹œํ‚ค๋„ค์š”', 'ํฌ์žฅ ์ƒํƒœ๋„ ์ข‹์Šต๋‹ˆ๋‹ค', '๋น ๋ฅด๊ฒŒ ๋ฐฐ์†ก๋˜๊ณ ']", + "answer": "๋น ๋ฅด๊ณ  ์ •ํ™•ํ•œ ๋ฐฐ์†ก๊ณผ ๊ผผ๊ผผํ•œ ํฌ์žฅ ๋•๋ถ„์— ๋งค์šฐ ๋งŒ์กฑํ•˜๋ฉฐ ์ž์ฃผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค." + }, + { + "query": "['๋„ˆ๋ฌด ๋ง›์žˆ์–ด์š”', '๋‹คํฌ์ดˆ์ฝœ๋ฆฟ์ด์ง€๋งŒ ๋‹ฌ์ฝคํ•ฉ๋‹ˆ๋‹ค', '๋‹ฌ์ง€๋„ ์“ฐ์ง€๋„ ์•Š๊ณ  ์ข‹์•„์š”', '๋‹ฌ๋‹ฌํ•˜๊ณ  ๋‹คํฌํ•ด์„œ ๊ตฟ', '๋‹ฌ์ง€ ์•Š๊ณ  ๋ง›์žˆ์–ด์š”', '๊ฐ€๊ฒฉ ๋Œ€๋น„ ๋ง›์žˆ๊ณ ', '๋ง›์žˆ์–ด์„œ ์ž์ฃผ ๋จน์–ด์š”', '๊ณ ๊ธ‰์ง€๋ฉด์„œ ๊ธฐ๋ถ„ ๋‚˜์œ ์“ด๋ง›์ด ์•„๋‹˜', '๋‹ฌ๋‹ฌํ•˜๋‹ˆ ๋ง›์žˆ์Šต๋‹ˆ๋‹ค', '๋ง›์žˆ๊ฒŒ ์ž˜ ๋จน์—ˆ์Šต๋‹ˆ๋‹ค', '์“ด ์ดˆ์ฝœ๋ฆฟ ์ข‹์•„ํ•ด์„œ ๊ตฌ๋งคํ•ฉ๋‹ˆ๋‹ค', '๋‹คํฌ์ดˆ์ฝœ๋ฆฟ ๋ง›์žˆ์Šต๋‹ˆ๋‹ค', '๋„ˆ๋ฌด ๋‹ฌ์ง€๋„ ์•Š๊ณ  ๋ง›์žˆ์–ด์š”', '์Œ‰์Œ€ํ•˜๊ฒŒ ๋ง›์žˆ์–ด์š”', '๋‹คํฌ์ดˆ์ฝœ๋ฆฟ ์ปคํ”ผ๋ž‘ ๋จน์œผ๋ฉด ์ •๋ง ๋ง›์žˆ์ฃ ', '๋ง›๋„ ๊ฐ€๊ฒฉ๋„ ์••๋„์  1์œ„', '๋ง›์žˆ๊ณ  ๋ง›์žˆ์–ด์š”', '์•„์ด๋“ค์ด ๋ง›์žˆ๊ฒŒ ์ž˜ ๋จน์—ˆ์Šต๋‹ˆ๋‹ค']", + "answer": "๋‹ฌ์ฝคํ•˜๋ฉด์„œ๋„ ์Œ‰์Œ€ํ•œ ๋‹คํฌ์ดˆ์ฝœ๋ฆฟ์˜ ๊ท ํ˜• ์žกํžŒ ๋ง›์ด ์ง„ํ•˜๊ณ  ๋ถ€๋“œ๋Ÿฌ์›Œ ์ž์ฃผ ์žฌ๊ตฌ๋งคํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค." + }, + { + "query": "['์—ญ์‹œ ์–ด๋‹ˆ์–ธ', '๋„ˆ๋ฌด ๋ง›์žˆ์–ด์š”', '์–ธ์ œ๋‚˜ ๋ง›์žˆ์–ด์š”', 'ํฌ์นด์นฉ ๋„ˆ๋ฌด ๋ง›์žˆ์–ด์š”', '๊ฐ์ž์นฉ ์ค‘์— ์ œ์ผ ๋ง›์žˆ์Œ', '์•„์ด๋“ค์ด ๋ง›์žˆ๋‹ค๊ณ  ํ•˜๋„ค์š”', '์–ด๋–ค ์ œํ’ˆ๋„ ๋”ฐ๋ผ์˜ฌ ์ˆ˜ ์—†๋Š” ๋ง›', '์–‘ํŒŒ๋ง›์ด ์ข‹์Œ', '์—ญ์‹œ ์–‘ํŒŒ๋ง›์ด ๋ง›์žˆ๋„ค์š”', '๋ง›์žˆ์–ด์„œ ํ•ญ์ƒ ๋–จ์–ด์ง€๋ฉด ์‹œํ‚ค๋Š” ์ œํ’ˆ์ด์—์š”', 'ํ•ญ์ƒ ๋จน์ง€๋งŒ ๋ง›์žˆ์–ด์š”', '๊ฐ์ž์นฉ ์ค‘์—์„œ๋Š” ํฌ์นด์นฉ์„ ๋”ฐ๋ผ๊ฐˆ ์ œํ’ˆ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์•„์š”', 'ํฌ์นด์นฉ ์–ด๋‹ˆ์–ธ๋ง› ์ข‹์•„์š”', '์˜ค๋ฆฌ์ง€๋„๋ณด๋‹ค ๋ง›์žˆ๋„ค์š”', '๋ง›์žˆ์–ด์„œ ํ•ญ์ƒ ๊ตฌ์ž…ํ•˜๋Š” ๊ณผ์ž์ž…๋‹ˆ๋‹ค', '๋ง›์žˆ์–ด์„œ ๋จน๊ธฐ ์ข‹์•„์š”', 'ํ•ญ์ƒ ๋ง›์žˆ๊ฒŒ ๋จน๊ณ  ์žˆ์–ด์š”']", + "answer": "์งญ์งคํ•˜๊ณ  ๊ณ ์†Œํ•œ ์–ด๋‹ˆ์–ธ ๋ง›์ด ๋›ฐ์–ด๋‚˜, ํฌ์นด์นฉ ์ค‘์—์„œ ๊ฐ€์žฅ ๋ง›์žˆ๊ณ  ํ•ญ์ƒ ์žฌ๊ตฌ๋งคํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค." + }, + { + "query": "['๋„ˆ๋ฌด ๋ง›์žˆ์–ด์š”', '์—ฌ์ „ํ•˜๋„ค์š”', '์—ฌ๊ธฐ ๊ฒƒ์ด ๋ง›์žˆ์–ด์š”', '๋‹ด๋ฐฑํ•˜๊ณ  ๋ง›์žˆ์–ด์š”', '์˜› ๋ง› ๊ทธ๋Œ€๋กœ๋„ค์š”', '์ •๋ง ๊ณ ์†Œํ•˜๋„ค์š”', '๋ง›์žˆ๋Š” ๊ณผ์ž์˜ˆ์š”', '์‚ด์ง ์งญ์งคํ•˜๋‹ˆ ๋ง›์žˆ์–ด์š”', '๊ฐ€๋” ๋จน์œผ๋ฉด ๋ง›์žˆ๋Š” ๊ณผ์ž์˜ˆ์š”', '์Šคํ…Œ๋””์…€๋Ÿฌ์ธ ๋งŒํผ ๋ง›์€ ๋ณด์žฅ๋ผ ์žˆ์ฃ ', '๋ง›์ด ๋ณ€ํ•˜์ง€ ์•Š์•„์„œ ์ข‹์•„์š”', '๋ง›์žˆ์–ด์„œ ์ž์ฃผ ๊ตฌ๋งคํ•ด์š”', '๋ง›์žˆ์–ด์„œ ๋จน๊ธฐ ์ข‹์•„์š”', '์งˆ๋ฆฌ์ง€ ์•Š๋Š” ๋ง›', '๊ณ ์†Œํ•˜๊ณ  ๋ง›์žˆ์–ด์š”', '๋‹ด๋ฐฑํ•˜๊ณ  ๊ณ ์†Œํ•˜๊ณ  ๋ง›์žˆ์–ด์š”', '๋ง›์žˆ๊ฒŒ ๋จน๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค', '๋„ˆ๋ฌด ๋ง›์žˆ์–ด์„œ', '์ถ”์–ต์˜ ๋ง›์ด์ฃ ', '์ปคํ”ผ ํ•œ ์ž”์ด ์ƒ๊ฐ๋‚˜๋Š” ๋ง›์ด์—์š”']", + "answer": "๋ณ€ํ•จ์—†๋Š” ๊ณ ์†Œํ•˜๊ณ  ๋‹ด๋ฐฑํ•œ ๋ง›์œผ๋กœ, ์–ธ์ œ ๋จน์–ด๋„ ๋ง›์žˆ์–ด ์ž์ฃผ ๊ตฌ๋งคํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค." + } + ] + \ No newline at end of file diff --git a/models/review/prompt/review_summarization/positive_prompt.txt b/models/review/prompt/review_summarization/positive_prompt.txt new file mode 100644 index 0000000..d100b27 --- /dev/null +++ b/models/review/prompt/review_summarization/positive_prompt.txt @@ -0,0 +1 @@ +๋‹น์‹ ์€ ์ „๋ฌธ ๋ฆฌ๋ทฐ ๋ถ„์„๊ฐ€์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์— ์ œ๊ณต๋œ ์†Œ๋น„์ž๋“ค์˜ ์›๋ณธ ๋ฆฌ๋ทฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ, ๊ธ์ •์ ์ธ ํ‰๊ฐ€์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ํ•˜๋‚˜์˜ ์™„์ „ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜์„ธ์š”. ์†Œ๋น„์ž๊ฐ€ ๊ฐ•์กฐํ•œ ๊ฐ•์ ๊ณผ ์žฅ์ ์„ ์ •์ค‘ํ•œ ๋†’์ž„๋ง๋กœ ํ‘œํ˜„ํ•˜์‹ญ์‹œ์˜ค. ์ถœ๋ ฅ์€ ๋ฐ˜๋“œ์‹œ JSON ํ˜•์‹์œผ๋กœ, ์˜ˆ: {"summarization": "<์š”์•ฝ>"} ํ˜•ํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/models/review/src/review_pipeline/__init__.py b/models/review/src/review_pipeline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/review/src/review_pipeline/aste_inference.py b/models/review/src/review_pipeline/aste_inference.py new file mode 100644 index 0000000..c57ef54 --- /dev/null +++ b/models/review/src/review_pipeline/aste_inference.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def run_aste_inference(config): + print("qwen_deepseek_14,32b_inference.py ํŒŒ์ผ๋กœ Inference๋ฅผ ์ง„ํ–‰ํ•˜์„ธ์š”.\n") + +if __name__ == "__main__": + run_aste_inference({"paths": {}}) diff --git a/models/review/src/review_pipeline/keyword_recommendation.py b/models/review/src/review_pipeline/keyword_recommendation.py new file mode 100644 index 0000000..75b48ff --- /dev/null +++ b/models/review/src/review_pipeline/keyword_recommendation.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ์žฌ์ •๋ ฌ ํŒŒ์ดํ”„๋ผ์ธ] +- ์ž…๋ ฅ CSV ํŒŒ์ผ ๋กœ๋ถ€ํ„ฐ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๋ณ„๋กœ ์ƒํ’ˆ์„ ์žฌ์ •๋ ฌํ•˜์—ฌ ์ตœ์ข… ์ถ”์ฒœ CSV ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค. +- ์ตœ์ข… ์ถœ๋ ฅ CSV ํŒŒ์ผ์€ ๋‹ค์Œ ์—ด๋กœ ๊ตฌ์„ฑ๋œ๋‹ค: + ์นดํ…Œ๊ณ ๋ฆฌ, ํ‚ค์›Œ๋“œ, ID, ์ƒํ’ˆ๋ช…, opinion ๊ฐœ์ˆ˜ +""" + +import os +import re +import json +import time +import requests +import pandas as pd +import numpy as np +from dotenv import load_dotenv +from utils.utils import load_data, expand_inference_data, sentenceBERT_embeddings, umap_reduce_embeddings, agglomerative_clustering, visualize_clustering, evaluate_clustering +from prompt.prompt_loader import load_prompt, load_fewshot + +######################################################### +# ๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ ๋ฐ ํ™•์žฅ ๊ด€๋ จ ํ•จ์ˆ˜ +######################################################### + +def filter_invalid_value(raw_value): + """ + unsloth_deepseek_32b ์นผ๋Ÿผ์˜ ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„, + - float(NaN) ๋˜๋Š” "[]"์ธ ๊ฒฝ์šฐ None ๋ฐ˜ํ™˜ + - ์ •์ƒ์ ์ธ JSON ๋ฌธ์ž์—ด์ด๋ฉด ํŒŒ์‹ฑ ํ›„ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด None ๋ฐ˜ํ™˜ + """ + if isinstance(raw_value, float) or (isinstance(raw_value, str) and raw_value.strip() == "[]"): + return None + try: + parsed = json.loads(raw_value) + if isinstance(parsed, list): + return parsed + else: + return None + except json.JSONDecodeError: + return None + +def load_and_prepare_data(config): + """ + config์— ๋ช…์‹œ๋œ ๊ฒฝ๋กœ์™€ ํŒŒ์ผ๋ช…์„ ํ™œ์šฉํ•˜์—ฌ ์ž…๋ ฅ CSV ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๊ณ , + unsloth_deepseek_32b ์นผ๋Ÿผ์˜ ๊ฐ’์„ ํŒŒ์‹ฑํ•œ ํ›„ ํ™•์žฅํ•œ๋‹ค. + ๋ถˆํ•„์š”ํ•œ ์—ด์€ ์‚ญ์ œํ•œ๋‹ค. + """ + train_data_path = os.path.join(config["paths"]["inference_dir"], config["inference_data"]) + df_infer = load_data(train_data_path) + df_infer["unsloth_deepseek_32b"] = df_infer["unsloth_deepseek_32b"].apply(filter_invalid_value) + df_infer = df_infer.dropna(subset=["unsloth_deepseek_32b"]) + aste_df = expand_inference_data(df_infer, "unsloth_deepseek_32b") + cols_to_drop = ['aste_hcx', 'aste_gpt', 'aste_golden_label'] + aste_df.drop(columns=cols_to_drop, errors='ignore', inplace=True) + print(f"๋ฆฌ๋ทฐ Opinion ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {aste_df.shape[0]}") + return aste_df + +def extract_product_id(review_id): + """ + review-ID ํ˜•์‹์ด "emart-(์ˆซ์ž)-(์ˆซ์ž)"์ธ ๊ฒฝ์šฐ, + ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„("emart-์ˆซ์ž")๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์ƒํ’ˆ ID๋กœ ์‚ฌ์šฉํ•œ๋‹ค. + """ + match = re.match(r"(emart-\d+)-\d+", review_id) + return match.group(1) if match else review_id + +######################################################### +# ํด๋Ÿฌ์Šคํ„ฐ๋ง ๋ฐ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ์ƒ์„ฑ ๊ด€๋ จ ํ•จ์ˆ˜ +######################################################### + +def get_sorted_clusters(df, cluster_column="cluster_label"): + """ + ํด๋Ÿฌ์Šคํ„ฐ ๋ผ๋ฒจ๋ณ„ ํฌ๊ธฐ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ์ •๋ ฌ๋œ DataFrame ๋ฐ˜ํ™˜ + """ + cluster_sizes = df[cluster_column].value_counts().reset_index() + cluster_sizes.columns = [cluster_column, "size"] + return cluster_sizes[cluster_sizes[cluster_column] != -1].sort_values(by="size", ascending=False) + +def hcx_generate_cluster_keywords(df, sorted_clusters, text_column="review", cluster_column="cluster_label"): + """ + ๊ฐ ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•ด HCX API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋Œ€ํ‘œ ํ‚ค์›Œ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. + """ + id_keyword_map = {} + for cluster in sorted_clusters[cluster_column]: + size = sorted_clusters[sorted_clusters[cluster_column] == cluster]['size'].values[0] + print(f"Cluster {cluster} (Size: {size})") + cluster_texts = df[df[cluster_column] == cluster][text_column] + unique_texts = list(set(cluster_texts.to_list()))[:50] + print("์ƒ˜ํ”Œ ๋ฆฌ๋ทฐ:", unique_texts) + keyword = robust_inference(str(unique_texts)) + id_keyword_map[cluster] = keyword.strip().strip('"') + print("์ƒ์„ฑ๋œ ํ‚ค์›Œ๋“œ:", id_keyword_map[cluster]) + print("-" * 80) + return id_keyword_map + +def generate_recommendations(df, id_keyword_map, selected_clusters): + """ + ์„ ํƒ๋œ ํด๋Ÿฌ์Šคํ„ฐ๋ณ„๋กœ, ๊ฐ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์—์„œ ์ตœ์†Œ 2ํšŒ ์ด์ƒ ๋“ฑ์žฅํ•œ ์ƒํ’ˆ์„ ๋Œ€์ƒ์œผ๋กœ + ์ถ”์ฒœ ์ƒํ’ˆ DataFrame์„ ์ƒ์„ฑํ•œ๋‹ค. + ์ตœ์ข… ์ถœ๋ ฅ ์—ด์€: + ์นดํ…Œ๊ณ ๋ฆฌ, ํ‚ค์›Œ๋“œ, ID, ์ƒํ’ˆ๋ช…, opinion ๊ฐœ์ˆ˜ + """ + result = pd.DataFrame(columns=["์นดํ…Œ๊ณ ๋ฆฌ", "ํ‚ค์›Œ๋“œ", "ID", "์ƒํ’ˆ๋ช…", "opinion ๊ฐœ์ˆ˜"]) + for cluster in selected_clusters: + # ์ƒํ’ˆ๋ช…๋ณ„ ๋นˆ๋„์ˆ˜ ๊ณ„์‚ฐ (5ํšŒ ์ด์ƒ ๋“ฑ์žฅํ•œ ๊ฒฝ์šฐ๋งŒ) + targets = df[df["cluster_label"] == cluster].value_counts(subset=["name"]) + targets = targets[targets >= 5] + items = [item[0] for item in targets.keys().tolist()] + # ๊ฐ ์ƒํ’ˆ์˜ review-ID์—์„œ ์ƒํ’ˆ ID ์ถ”์ถœ + ids = [extract_product_id(df[df["name"] == name]["review-ID"].values[0]) for name in items] + # ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๊ฐ ์ƒํ’ˆ์˜ "category" ์—ด์˜ ์ฒซ ๋ฒˆ์งธ ๊ฐ’ ์‚ฌ์šฉ + categories = [df[df["name"] == name]["category"].values[0] for name in items] + keyword = id_keyword_map.get(cluster, "") + for item, count, pid, cat in zip(items, targets.tolist(), ids, categories): + temp_df = pd.DataFrame({ + "์นดํ…Œ๊ณ ๋ฆฌ": [cat], + "ํ‚ค์›Œ๋“œ": [keyword], + "ID": [pid], + "์ƒํ’ˆ๋ช…": [item], + "opinion ๊ฐœ์ˆ˜": [count] + }) + result = pd.concat([result, temp_df], ignore_index=True) + return result + +def get_prompt_and_fewshot(): + """ + aspect์™€ sentiment์— ๋”ฐ๋ฅธ ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. + ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋Š” prompt ํด๋” ๋‚ด์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ๊ด€๋ฆฌ๋œ๋‹ค. + """ + prompt = load_prompt(prompt_filename="recommendation_prompt.txt", + prompt_dir="./prompt/keyword_recommendation/") + fewshot = load_fewshot(fewshot_filename="recommendation_fewshot.json", + prompt_dir="./prompt/keyword_recommendation/") + return prompt, fewshot + +def robust_inference(query, retry_delay=2): + """ + API ์š”์ฒญ์ด ์‹คํŒจํ•˜๋ฉด ์žฌ์‹œ๋„ํ•˜๋Š” ํ•จ์ˆ˜ (์ถ”์ฒœ ํ‚ค์›Œ๋“œ ์ƒ์„ฑ์„ ์œ„ํ•ด HCX API ํ˜ธ์ถœ) + """ + while True: + result = inference(query) + if not (result.startswith("API Error") or result.startswith("Request Error")): + return result + print("API ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋‹ค์‹œ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค...") + time.sleep(retry_delay) + +def inference(query): + load_dotenv(os.path.expanduser("~/.env")) + AUTHORIZATION = os.getenv("AUTHORIZATION") + X_NCP_CLOVASTUDIO_REQUEST_ID = os.getenv("X_NCP_CLOVASTUDIO_REQUEST_ID") + if not AUTHORIZATION or not X_NCP_CLOVASTUDIO_REQUEST_ID: + raise ValueError("ํ•„์ˆ˜ API ์ธ์ฆ ์ •๋ณด๊ฐ€ .env์— ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + headers = { + 'Authorization': AUTHORIZATION, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': X_NCP_CLOVASTUDIO_REQUEST_ID, + 'Content-Type': 'application/json; charset=utf-8', + } + prompt, fewshot = get_prompt_and_fewshot() + + messages = [{"role": "system", "content": prompt}] + for example in fewshot: + # ๋งŒ์•ฝ fewshot์˜ query๊ฐ€ ๋ฆฌ์ŠคํŠธ๋ฉด join + query_text = " ".join(example["query"]) if isinstance(example["query"], list) else example["query"] + messages.append({"role": "user", "content": query_text}) + messages.append({"role": "assistant", "content": example["answer"]}) + messages.append({"role": "user", "content": query}) + + request_data = { + 'messages': messages, + 'topP': 0.8, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.5, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': False, + 'seed': 42 + } + try: + response = requests.post("https://clovastudio.stream.ntruss.com/testapp/v1/chat-completions/HCX-003", headers=headers, json=request_data) + response.raise_for_status() + response_json = response.json() + if response_json.get("status", {}).get("code") == "20000": + output_text = response_json["result"]["message"]["content"] + return output_text + else: + return f"API Error: {response_json.get('status', {}).get('message')}" + except requests.exceptions.RequestException as e: + return f"Request Error: {e}" + +######################################################### +# ์ตœ์ข… ์ถ”์ฒœ ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ํ•จ์ˆ˜ +######################################################### + +def run_keyword_recommendation(config): + print("\n[์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ์žฌ์ •๋ ฌ ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘]\n") + + # ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ + aste_df = load_and_prepare_data(config) + + # ๊ธ์ • ์˜๊ฒฌ๋งŒ ์„ ํƒ (์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋Š” ๊ธ์ • ๋ฆฌ๋ทฐ ๊ธฐ๋ฐ˜) + infer_pos = aste_df[aste_df["sentiment"] == "๊ธ์ •"] + infer_pos.loc[:, 'category'] = infer_pos['category'].replace({'์•„์ด๊ฐ„์‹': '๋ผ๋ฉด/๊ฐ„ํŽธ์‹'}) + + category_map = { + "๊ณผ์ž/๋น™๊ณผ": "snacks", + "๋ผ๋ฉด/๊ฐ„ํŽธ์‹": "meals" + } + + infer_pos["category"] = infer_pos["category"].map(category_map).fillna(infer_pos["category"]) + + # ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ DataFrame ๋ถ„ํ•  + category_dfs = {category: df for category, df in infer_pos.groupby("category")} + + all_recommendations = [] # ์ „์ฒด ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ๋ฆฌ์ŠคํŠธ + + # ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ + for category, df_cat in category_dfs.items(): + print(f"\n[์นดํ…Œ๊ณ ๋ฆฌ: {category} ์ฒ˜๋ฆฌ ์‹œ์ž‘]\n") + + # 1) ์ž„๋ฒ ๋”ฉ ๋งคํŠธ๋ฆญ์Šค ์ƒ์„ฑ + embedding_file = os.path.join(config["paths"]["embedding_dir"], f"deepseek_inference_{category}.npy") + embedding_matrix = sentenceBERT_embeddings(embedding_file, df=df_cat, column="opinion") + + # 2) UMAP ์ฐจ์› ์ถ•์†Œ + reduced_embeddings = umap_reduce_embeddings(embedding_matrix, n_components=256) + + # 3) ํด๋Ÿฌ์Šคํ„ฐ๋ง (Agglomerative Clustering ์‚ฌ์šฉ, ์ž„๊ณ„๊ฐ’ ์กฐ์ •) + cluster_labels = agglomerative_clustering(reduced_embeddings, distance_threshold=21.5) + df_cat['cluster_label'] = cluster_labels + + # 4) ํด๋Ÿฌ์Šคํ„ฐ๋ณ„ ์ •๋ ฌ ๋ฐ ํ‚ค์›Œ๋“œ ์ƒ์„ฑ + sorted_clusters = get_sorted_clusters(df_cat, cluster_column="cluster_label") + id_keyword_map = hcx_generate_cluster_keywords(df_cat, sorted_clusters, text_column="review", cluster_column="cluster_label") + + # 5) ์ถ”์ฒœ ๋Œ€์ƒ ํด๋Ÿฌ์Šคํ„ฐ ์„ ํƒ (๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ์‚ฌ์šฉ) + selected_clusters = sorted_clusters["cluster_label"].tolist() + + # 6) ์ถ”์ฒœ ์ƒํ’ˆ ์ƒ์„ฑ + recommendation_df = generate_recommendations(df_cat, id_keyword_map, selected_clusters) + final_columns = ["์นดํ…Œ๊ณ ๋ฆฌ", "ํ‚ค์›Œ๋“œ", "ID", "์ƒํ’ˆ๋ช…", "opinion ๊ฐœ์ˆ˜"] + recommendation_df = recommendation_df[final_columns] + + # 7) ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ CSV ํŒŒ์ผ ์ €์žฅ + output_file = os.path.join(config["paths"]["final_outputs_dir"], f"recommendation_{category}.csv") + recommendation_df.to_csv(output_file, index=False) + print(f"์นดํ…Œ๊ณ ๋ฆฌ {category}์˜ ์ถ”์ฒœ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {output_file}") + + all_recommendations.append(recommendation_df) + print(f"\n[์นดํ…Œ๊ณ ๋ฆฌ: {category} ์ฒ˜๋ฆฌ ์™„๋ฃŒ]\n") + + return all_recommendations + +if __name__ == "__main__": + # config๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฒฝ๋กœ ๋ฐ ํŒŒ์ผ๋ช…์„ ๋ชจ๋“ˆํ™” + config = { + "paths": { + "inference_dir": "./data/aste/inference", + "embedding_dir": "./data/embedding_matrics", + "final_outputs_dir": "../final_outputs" + }, + "inference_data": "inferenced_reviews_snacks_meals_temp.csv" + } + run_keyword_recommendation(config) diff --git a/models/review/src/review_pipeline/qwen_deepseek_14b_inference.py b/models/review/src/review_pipeline/qwen_deepseek_14b_inference.py new file mode 100644 index 0000000..3a28274 --- /dev/null +++ b/models/review/src/review_pipeline/qwen_deepseek_14b_inference.py @@ -0,0 +1,151 @@ +import time +import torch +import numpy as np +import pandas as pd +from tqdm import tqdm +from ast import literal_eval +from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig + +from utils.evaluate import evaluate_aste + + +PROMPT = """๋‹น์‹ ์€ ์‹ํ’ˆ ๋ฆฌ๋ทฐ์˜ ๊ฐ์„ฑ ๋ถ„์„ ๋ฐ ํ‰๊ฐ€ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ๋ทฐ์—์„œ ์†์„ฑ๊ณผ ํ‰๊ฐ€, ๊ฐ์„ฑ์„ ์ถ”์ถœํ•˜์„ธ์š”. + +### ์ž‘์—… ๋ชฉํ‘œ: +1. ์ž…๋ ฅ์œผ๋กœ ์ฃผ์–ด์ง€๋Š” ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•˜์„ธ์š”. +2. JSON ํ˜•์‹์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. + ```json + [ + {{"์†์„ฑ": "<์†์„ฑ๋ช…1>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ1>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + {{"์†์„ฑ": "<์†์„ฑ๋ช…2>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ2>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + ... + ] + ``` + +์†์„ฑ์€ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค: ["์ƒํ’ˆ", "๋ฐฐ์†ก", "๊ฐ€๊ฒฉ", "๋ง›", "์‹ ์„ ๋„", "์–‘", "ํฌ์žฅ"]. +๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์†์„ฑ์ด ํ•„์š”ํ•˜๋ฉด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +๋ชจ๋“  ์‹ํ’ˆ๋ช…์€ "์ƒํ’ˆ"์œผ๋กœ ํ†ต์ผํ•ฉ๋‹ˆ๋‹ค. + +### ์„ธ๋ถ€ ๊ทœ์น™: +- ๊ฐ์ • ๋ถ„์„ + - ๋ฆฌ๋ทฐ์—์„œ ๊ฐ์ •์ด ๊ธ์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "๊ธ์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ๋ถ€์ •์ ์ธ ํ‘œํ˜„์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ "๊ฐ์ •": "๋ถ€์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€๊ฐ€ ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "์ค‘๋ฆฝ"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + +- ํ‰๊ฐ€ ๋ฌธ๊ตฌ ์ •์ œ + - ๋ฆฌ๋ทฐ์—์„œ ๋‚˜ํƒ€๋‚œ ์ฃผ์š” ํ‰๊ฐ€๋ฅผ ๊ฐ„๊ฒฐํ•œ ๋ฌธ์žฅ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + - ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„์€ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€ ๋ฌธ๊ตฌ๋Š” '~๋‹ค.'๋กœ ๋๋‚˜๋Š” ํ˜„์žฌํ˜•, ํ‰์„œ๋ฌธ์œผ๋กœ ๋‹ต๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '์ข‹์Šต๋‹ˆ๋‹ค.' ๊ฐ€ ์•„๋‹Œ '์ข‹๋‹ค.' ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + +- ์˜ˆ์™ธ ์‚ฌํ•ญ + - ์ƒํ’ˆ ์‚ฌ์šฉ ํ›„๊ธฐ๊ฐ€ ์•„๋‹Œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์˜ˆ์ƒ์ด๋‚˜ ๊ธฐ๋Œ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ„๋ฆฌํ•˜์—ฌ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค. + - ๋ณตํ•ฉ์ ์ธ ํ‰๊ฐ€๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ๊ฐ JSON ํ•ญ๋ชฉ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '๋ฐฐ์†ก์ด ์•ˆ์ „ํ•˜๊ณ  ๋นจ๋ž์–ด์š”'์˜ ๊ฒฝ์šฐ '์•ˆ์ „ํ•˜๋‹ค.' ์™€ '๋น ๋ฅด๋‹ค.' ๋‘ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + +### ์ž…๋ ฅ: +{review} + +""" + + +def prepare_data(path): + data_df = pd.read_csv(path) + return data_df + +def extract_aste(model_size, quant_type, data_df, col_name): + """ + model_size: 14 or 8 + quant_type: 8 or 4 + data_df: DataFrame + """ + + # model_name = f"deepseek-ai/DeepSeek-R1-Distill-Qwen-{model_size}B" + model_name = "deepseek_14b_custom_eval" + + if not quant_type: + bnb_config = None + elif quant_type == 4: + bnb_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_compute_dtype=torch.float32 + ) + else: + bnb_config = BitsAndBytesConfig( + load_in_8bit=True + ) + + tokenizer = AutoTokenizer.from_pretrained(model_name) + model = AutoModelForCausalLM.from_pretrained( + model_name, + quantization_config=bnb_config, + device_map="auto" + ) + + total_time = 0 + for idx, row in tqdm(data_df[pd.isna(data_df[col_name])].iterrows()): + txt = row["processed"] + # answer = row["aste_golden_label"] + + input_text = PROMPT.format(review=txt) + print(row["review-ID"], txt) + + start_time = time.time() + inputs = tokenizer(input_text, return_tensors="pt").to("cuda") + output = model.generate(**inputs, + max_new_tokens=512, + temperature=0.6, + top_p=0.95, + do_sample=True) + output = tokenizer.decode(output[0]) + + try: + aste = str(literal_eval(output.split("")[1].split("```json")[1].split("```<")[0])) + # thinking = output.split("")[1].split("")[0] + except Exception as e: + aste = np.nan + # thinking = output.split("")[1] + + spent = time.time() - start_time + + # print(f"\nreasoning: \n{thinking}") + print(f"\naste: {aste}") + # print(f"\nanswer: {answer}") + print(f"\n{spent}") + print("\n=============================================================\n") + + total_time += spent + data_df.loc[idx, col_name] = aste + # data_df.loc[idx, "thinking"] = thinking + + data_df.to_csv("./data/aste/inference/deepseek_14b_inference.csv", index=False) + print(f"total time: {total_time / len(data_df)}") + + +if __name__ == "__main__": + # data_path = "processed_except_GL.csv" # + data_path = "./data/aste/eval/aste_annotation_100_golden_label.csv" + col_name = "inference" + + data_df = prepare_data(data_path) + data_df[col_name] = None + + start_time = time.time() + extract_aste(14, 4, data_df, col_name) + first_lap = time.time() - start_time + + num_null = 0 + while data_df[col_name].isna().sum() > 0: + num_null += data_df[col_name].isna().sum() + extract_aste(14, 4, data_df, col_name) + end_time = time.time() - start_time + + print(f"\nํ•œ ๋ฐ”ํ€ด: {first_lap}์ดˆ, ์ด: {end_time}์ดˆ, ํ‰๊ท : {end_time / 100}์ดˆ") + print(f"์ด {num_null}๊ฐœ์˜ ์ถ”๋ก  ์‹คํŒจ ํ›„ ์žฌ์‹œ๋„") + + print("\n=== Start Evaluation ===\n") + + evaluate_aste( + data_df, + golden_label_col="aste_golden_label", + model_prediction_col=col_name, + ) + \ No newline at end of file diff --git a/models/review/src/review_pipeline/qwen_deepseek_32b_inference.py b/models/review/src/review_pipeline/qwen_deepseek_32b_inference.py new file mode 100644 index 0000000..fb8f5cb --- /dev/null +++ b/models/review/src/review_pipeline/qwen_deepseek_32b_inference.py @@ -0,0 +1,241 @@ +import argparse +import pandas as pd +import time +import re +import json +from tqdm import tqdm + +from unsloth import FastLanguageModel +from utils.evaluate import evaluate_aste # ํ‰๊ฐ€ ํ•จ์ˆ˜ ์ž„ํฌํŠธ (๊ฒฝ๋กœ์— ๋งž๊ฒŒ ์ˆ˜์ •) + + +def load_model(): + """๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.""" + model, tokenizer = FastLanguageModel.from_pretrained( + model_name='./output_zeroshot/checkpoint-336', + max_seq_length=2048, + dtype=None, + load_in_4bit=True, + temperature=0.6 + ) + FastLanguageModel.for_inference(model) + return model, tokenizer + + +PROMPT_TEMPLATE = """๋‹น์‹ ์€ ์‹ํ’ˆ ๋ฆฌ๋ทฐ์˜ ๊ฐ์„ฑ ๋ถ„์„ ๋ฐ ํ‰๊ฐ€ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ๋ทฐ์—์„œ ์†์„ฑ๊ณผ ํ‰๊ฐ€, ๊ฐ์„ฑ์„ ์ถ”์ถœํ•˜์„ธ์š”. + +### ์ž‘์—… ๋ชฉํ‘œ: +1. ์ž…๋ ฅ์œผ๋กœ ์ฃผ์–ด์ง€๋Š” ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•˜์„ธ์š”. +2. JSON ํ˜•์‹์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. + ```json + [ + {{"์†์„ฑ": "<์†์„ฑ๋ช…1>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ1>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + {{"์†์„ฑ": "<์†์„ฑ๋ช…2>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ2>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + ... + ] + ``` + +์†์„ฑ์€ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค: ["์ƒํ’ˆ", "๋ฐฐ์†ก", "๊ฐ€๊ฒฉ", "๋ง›", "์‹ ์„ ๋„", "์–‘", "ํฌ์žฅ"]. +๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์†์„ฑ์ด ํ•„์š”ํ•˜๋ฉด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +๋ชจ๋“  ์‹ํ’ˆ๋ช…์€ "์ƒํ’ˆ"์œผ๋กœ ํ†ต์ผํ•ฉ๋‹ˆ๋‹ค. + +### ์„ธ๋ถ€ ๊ทœ์น™: +- ๊ฐ์ • ๋ถ„์„ + - ๋ฆฌ๋ทฐ์—์„œ ๊ฐ์ •์ด ๊ธ์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "๊ธ์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ๋ถ€์ •์ ์ธ ํ‘œํ˜„์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ "๊ฐ์ •": "๋ถ€์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€๊ฐ€ ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "์ค‘๋ฆฝ"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + +- ํ‰๊ฐ€ ๋ฌธ๊ตฌ ์ •์ œ + - ๋ฆฌ๋ทฐ์—์„œ ๋‚˜ํƒ€๋‚œ ์ฃผ์š” ํ‰๊ฐ€๋ฅผ ๊ฐ„๊ฒฐํ•œ ๋ฌธ์žฅ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + - ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„์€ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€ ๋ฌธ๊ตฌ๋Š” '~๋‹ค.'๋กœ ๋๋‚˜๋Š” ํ˜„์žฌํ˜•, ํ‰์„œ๋ฌธ์œผ๋กœ ๋‹ต๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '์ข‹์Šต๋‹ˆ๋‹ค.' ๊ฐ€ ์•„๋‹Œ '์ข‹๋‹ค.' ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + +- ์˜ˆ์™ธ ์‚ฌํ•ญ + - ์ƒํ’ˆ ์‚ฌ์šฉ ํ›„๊ธฐ๊ฐ€ ์•„๋‹Œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์˜ˆ์ƒ์ด๋‚˜ ๊ธฐ๋Œ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ„๋ฆฌํ•˜์—ฌ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค. + - ๋ณตํ•ฉ์ ์ธ ํ‰๊ฐ€๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ๊ฐ JSON ํ•ญ๋ชฉ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '๋ฐฐ์†ก์ด ์•ˆ์ „ํ•˜๊ณ  ๋นจ๋ž์–ด์š”'์˜ ๊ฒฝ์šฐ '์•ˆ์ „ํ•˜๋‹ค.' ์™€ '๋น ๋ฅด๋‹ค.' ๋‘ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + +### ์˜ˆ์‹œ: +์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ฌ๊ณ ํ•˜๋˜, ๋ถˆํ•„์š”ํ•œ ๊ณผ์ •์„ ์ƒ๋žตํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋‹ต๋ณ€ํ•˜์„ธ์š”. + +์˜ˆ์‹œ 1. +์ด๋ฒˆ์— ๋งŽ์ด ์ฃผ๋ฌธํ–ˆ๋Š”๋ฐ ์ž˜ ๋„์ฐฉํ–ˆ๊ณ ์š” ๊ณ„๋ž€๋„ ๊นจ์ง„ ๊ฑฐ ์—†์ด ์ž˜ ๋ฐ›์•˜์–ด์š” ์œ ํ†ต ๊ธฐํ•œ๋„ ๋„‰๋„‰ํ•˜๊ณ  ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. +[{{'์†์„ฑ': '๋ฐฐ์†ก', 'ํ‰๊ฐ€': '์ž˜ ๋„์ฐฉํ–ˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๋ฐฐ์†ก', 'ํ‰๊ฐ€': '์•ˆ์ „ํ•˜๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์œ ํ†ต๊ธฐํ•œ์ด ๋„‰๋„‰ํ•˜๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '๋งŒ์กฑ์Šค๋Ÿฝ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 2. +๋ฐฐ์†ก ๋น ๋ฅด๊ณ  ์ข‹์Šต๋‹ˆ๋‹ค. +[{{'์†์„ฑ': '๋ฐฐ์†ก', 'ํ‰๊ฐ€': '๋น ๋ฅด๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๋ฐฐ์†ก', 'ํ‰๊ฐ€': '์ข‹๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 3. +์›๋ž˜ ์ž˜ ๋จน๋˜ ๊ฑฐ๋ผ ์žฌ๊ตฌ๋งค์ž…๋‹ˆ๋‹ค. +[{{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์ž์ฃผ ๋จน๋Š”๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์žฌ๊ตฌ๋งค๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 4. +๋น„๊ตํ•ด ๋ณด๋ ค๊ณ  ์‚ฌ ๋ดค์–ด์š”. ์‹ ์„ ํ•˜๊ณ  ๋ง›์žˆ๋„ค์š”. +[{{"์†์„ฑ": "์ƒํ’ˆ", "ํ‰๊ฐ€": "๋น„๊ตํ•ด๋ณด๋ ค ๊ตฌ๋งคํ–ˆ๋‹ค.", "๊ฐ์ •": "์ค‘๋ฆฝ"}}, {{'์†์„ฑ': '์‹ ์„ ๋„', 'ํ‰๊ฐ€': '์‹ ์„ ํ•˜๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '๋ง›์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 5. +๋ฆฌ๋ทฐ ๋ณด๊ณ  ์ฃผ๋ฌธํ–ˆ๋Š”๋ฐ ๊ธฐ๋Œ€๋˜๋„ค์š”. +[] + +์˜ˆ์‹œ 6. +๋…ธ๋ธŒ๋žœ๋“œ ์ €๋ ดํ•˜๊ณ  ์ข‹์•„์š”. +[{{'์†์„ฑ': '๊ฐ€๊ฒฉ', 'ํ‰๊ฐ€': '์ €๋ ดํ•˜๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์ข‹๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 7. +์น˜์ฆˆํ”ผ์ž๋ฅผ ์ข‹์•„ํ•ด์„œ ๋ง›์žˆ๊ฒŒ ์ž˜ ๋จน์—ˆ์–ด์š” ๋น„๊ต์  ๋„ํ†ฐํ•ด์„œ ๊ธˆ๋ฐฉ ๋ฐฐ ๋ถˆ๋Ÿฌ์ ธ์š” ๋ง›์žˆ๊ณ  ๋ฐฐ๋ถ€๋ฅด๊ฒŒ ์ž˜ ๋จน์—ˆ์–ด์š”. +[{{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '๋ง›์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์–‘', 'ํ‰๊ฐ€': '๋„ํ†ฐํ•ด์„œ ๊ธˆ๋ฐฉ ๋ฐฐ๋ถ€๋ฅด๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์ž˜ ๋จน์—ˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 8. +์šฐ์œ ๋ž‘ ๋จน์–ด๋„ ๋ง›์žˆ๊ณ  ๊ทธ๋ƒฅ ๊ณผ์ž์ฒ˜๋Ÿผ ๋จน์–ด๋„ ๋ง›์žˆ์–ด์š”. +[{{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '์šฐ์œ ๋ž‘ ๋จน์œผ๋ฉด ๋ง›์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '๊ทธ๋ƒฅ ๋จน์–ด๋„ ๋ง›์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 9. +์ƒˆ์šฐ๊นก์ด ๋‹น๊ธธ ๋•Œ๊ฐ€ ์žˆ์–ด์š” ๊ฐ•์ถ”๋“œ๋ฆฝ๋‹ˆ๋‹ค ์žฌ๊ตฌ๋งคํ•˜๋ ค๊ณ ์š” ์ €๋ ดํ•˜๊ฒŒ ์ž˜ ์ƒ€์–ด์š”. +[{{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '๋‹น๊ธฐ๋Š” ๋ง›์ด๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์ถ”์ฒœํ•œ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': '์žฌ๊ตฌ๋งค ์˜์‚ฌ ์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๊ฐ€๊ฒฉ', 'ํ‰๊ฐ€': '์ €๋ ดํ•˜๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +์˜ˆ์‹œ 10. +๋–จ์–ด์ง€๋ฉด ๋‹ค์‹œ ์ฑ„์›Œ ๋„ฃ๊ณ  ๋จน๊ณ  ์žˆ์–ด์š” ๋„ˆ๋ฌด ๋ง›์žˆ์–ด์š”. +[{{'์†์„ฑ': '์ƒํ’ˆ', 'ํ‰๊ฐ€': 'ํ•ญ์ƒ ์žฌ๊ตฌ๋งคํ•œ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}, {{'์†์„ฑ': '๋ง›', 'ํ‰๊ฐ€': '๋ง›์žˆ๋‹ค.', '๊ฐ์ •': '๊ธ์ •'}}] + +### ์ž…๋ ฅ: +{review} + +""" + + +def inference(review_text: str, model, tokenizer): + """ + ์ž…๋ ฅ ๋ฆฌ๋ทฐ์— ๋Œ€ํ•ด ๋ชจ๋ธ์„ ํ†ตํ•œ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + ๋ฐ˜ํ™˜: chain-of-thought(cot)์™€ ์‹ค์ œ ๋‹ต๋ณ€(ans) + """ + messages = [{"role": "user", "content": PROMPT_TEMPLATE.format(review=review_text)}] + print("์ž…๋ ฅ ๋ฉ”์‹œ์ง€:", messages) + + # ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ ์ ์šฉ (๋ฌธ์ž์—ด ์ƒ์„ฑ) + formatted_text = tokenizer.apply_chat_template( + messages, + tokenize=False, + add_generation_prompt=True + ) + + model_inputs = tokenizer([formatted_text], return_tensors="pt").to(model.device) + generated_ids = model.generate( + **model_inputs, + max_new_tokens=512 + ) + # ์ž…๋ ฅ ํ† ํฐ ๊ธธ์ด ์ดํ›„์˜ ํ† ํฐ๋งŒ ์ถ”์ถœ + generated_ids = [ + output_ids[len(input_ids):] + for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) + ] + response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] + + # chain-of-thought์™€ ์ตœ์ข… ๋‹ต๋ณ€ ๋ถ„๋ฆฌ ( ํƒœ๊ทธ ๊ธฐ์ค€) + cot = response.split("")[0].strip() + ans = response.split("")[-1].strip() + + return cot, ans + +def post_process_answer(answer: str): + """ + ๋ชจ๋ธ์˜ ๋‹ต๋ณ€์—์„œ JSON ์ฝ”๋“œ ๋ธ”๋ก์„ ์ถ”์ถœํ•˜๊ณ  ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค. + """ + match = re.search(r"```json\s*(.*?)\s*```", answer, re.DOTALL) + if match: + json_str = match.group(1) + else: + json_str = answer # ์ฝ”๋“œ ๋ธ”๋ก์ด ์—†์œผ๋ฉด ์ „์ฒด ํ…์ŠคํŠธ ์‚ฌ์šฉ + + try: + data = json.loads(json_str) + except json.JSONDecodeError as e: + print("JSON ํŒŒ์‹ฑ ์—๋Ÿฌ:", e) + data = None + return data + +def run_inference_on_dataframe(df: pd.DataFrame, model, tokenizer, num_samples: int = None) -> pd.DataFrame: + """ + DataFrame์˜ ๊ฐ ๋ฆฌ๋ทฐ์— ๋Œ€ํ•ด ๋ชจ๋ธ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ฒฐ๊ณผ ๋ฐ ์†Œ์š” ์‹œ๊ฐ„์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. + JSON ํŒŒ์‹ฑ์— ์‹คํŒจํ•œ ๊ฒฝ์šฐ ์ตœ๋Œ€ 20ํšŒ๊นŒ์ง€ ์žฌ์‹œ๋„ํ•˜๋ฉฐ, ๊ฐ ๋ฆฌ๋ทฐ๋ณ„ ์‹คํŒจ ํšŸ์ˆ˜๋ฅผ failure_counts ๋ฆฌ์ŠคํŠธ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + """ + times = [] + failure_counts = [] # ๊ฐ ๋ฆฌ๋ทฐ๋ณ„ ์žฌ์‹œ๋„(์‹คํŒจ) ํšŸ์ˆ˜๋ฅผ ์ €์žฅํ•  ๋ฆฌ์ŠคํŠธ + if num_samples is not None: + df = df.head(num_samples) + + for idx, row in tqdm(df.iterrows(), total=df.shape[0], desc="Inference"): + review_text = row["processed"] + start_time = time.time() + attempts = 0 # ์žฌ์‹œ๋„ ํšŸ์ˆ˜ (์„ฑ๊ณต ์‹œ 0์ด๋ฉด ์ตœ์ดˆ ์‹œ๋„์— ์„ฑ๊ณตํ•œ ๊ฒƒ) + ans_json = None + + # ์ตœ๋Œ€ 20ํšŒ ์‹œ๋„ (์ตœ์ดˆ ์‹œ๋„ ํฌํ•จํ•˜์—ฌ ์ตœ๋Œ€ 20๋ฒˆ) + while attempts < 20: + cot, ans = inference(review_text, model, tokenizer) + ans_json = post_process_answer(ans) + print(ans_json) + if ans_json is not None: + break + attempts += 1 + print(f"JSON ์ถ”์ถœ ์‹คํŒจ, ์žฌ์‹œ๋„ {attempts}ํšŒ") + + if ans_json is None: + print("์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜(20ํšŒ)๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋ฅผ None์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.") + elapsed = time.time() - start_time + times.append(elapsed) + failure_counts.append(attempts) + print(f"์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {elapsed:.2f}์ดˆ, ์‹คํŒจ ํšŸ์ˆ˜: {attempts}") + print("\n" + "=" * 60 + "\n") + + # ๊ฒฐ๊ณผ๋ฅผ ์ƒˆ๋กœ์šด ์ปฌ๋Ÿผ์— ์ €์žฅ (JSON ๋ฌธ์ž์—ด๋กœ) + df.loc[idx, "unsloth_deepseek_32b"] = json.dumps(ans_json, ensure_ascii=False) + + print("์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ ๋ฆฌ์ŠคํŠธ:", times) + if times: + print("ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {:.2f}์ดˆ".format(sum(times) / len(times))) + print("๊ฐ ๋ฆฌ๋ทฐ๋ณ„ ์žฌ์‹œ๋„ ์‹คํŒจ ํšŸ์ˆ˜:", failure_counts) + return df + +def main(): + parser = argparse.ArgumentParser(description="aste ๋ชจ๋ธ ์ถ”๋ก  ๋ฐ ํ‰๊ฐ€ ์Šคํฌ๋ฆฝํŠธ") + parser.add_argument("--input_csv", type=str, required=True, + help="์ž…๋ ฅ CSV ํŒŒ์ผ ๊ฒฝ๋กœ (์˜ˆ: aste_annotation_100_gpt_after.csv)") + parser.add_argument("--output_csv", type=str, default=None, + help="์ถœ๋ ฅ CSV ํŒŒ์ผ ๊ฒฝ๋กœ (์ €์žฅํ•  ๊ฒฝ์šฐ)") + parser.add_argument("--num_samples", type=int, default=None, + help="์ถ”๋ก ํ•  ์ƒ˜ํ”Œ ๊ฐœ์ˆ˜ (ID ํ•„ํ„ฐ๋ง ํ›„ ์ง€์ • ๊ฐ€๋Šฅ)") + parser.add_argument("--selected_review_ids", type=str, nargs="*", default=None, + help="ํ‰๊ฐ€ํ•  ํŠน์ • review-ID ๋ชฉ๋ก (์˜ˆ: emart-118 emart-50 ...)") + args = parser.parse_args() + + model, tokenizer = load_model() + + df = pd.read_csv(args.input_csv) + print(f"์ด {len(df)}๊ฐœ์˜ ๋ฆฌ๋ทฐ ๋กœ๋“œ๋จ.") + + # ๋งŒ์•ฝ ํŠน์ • ID๋“ค์ด ์ง€์ •๋˜์—ˆ๋‹ค๋ฉด ํ•„ํ„ฐ๋ง + if args.selected_review_ids: + df = df[df["review-ID"].isin(args.selected_review_ids)] + print(f"์„ ํƒ๋œ ๋ฆฌ๋ทฐ: {df['review-ID'].tolist()}") + print(f"์ด {len(df)}๊ฐœ์˜ ๋ฆฌ๋ทฐ๊ฐ€ ์„ ํƒ๋จ.") + + # ๋งŒ์•ฝ num_samples ์˜ต์…˜์ด ์žˆ๋‹ค๋ฉด head()๋ฅผ ์‚ฌ์šฉ (์„ ํƒ๋œ ID์˜ ๊ฐœ์ˆ˜๋ณด๋‹ค ์ž‘์œผ๋ฉด ์ „์ฒด๊ฐ€ ์‚ฌ์šฉ๋จ) + if args.num_samples is not None: + df = df.head(args.num_samples) + + print("์ตœ์ข… ๋ฐ์ดํ„ฐ ์ˆ˜:", len(df)) + + df = run_inference_on_dataframe(df, model, tokenizer, num_samples=args.num_samples) + + evaluate_aste( + df.head(args.num_samples), + golden_label_col="aste_golden_label", + model_prediction_col="unsloth_deepseek_32b" + ) + + if args.output_csv: + df.to_csv(args.output_csv, index=False) + print(f"๊ฒฐ๊ณผ๊ฐ€ {args.output_csv}์— ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/review/src/review_pipeline/review_summarization.py b/models/review/src/review_pipeline/review_summarization.py new file mode 100644 index 0000000..3c87c0e --- /dev/null +++ b/models/review/src/review_pipeline/review_summarization.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[๋ฆฌ๋ทฐ ์š”์•ฝ ์ถ”์ถœ ํŒŒ์ดํ”„๋ผ์ธ] +- ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‘ ๊ฐœ์˜ aspect๋ณ„ ์š”์•ฝ์„ ์ƒ์„ฑ: + 1. "๋ง›" (๋‹จ๋…) + 2. "๋ฐฐ์†ก"๊ณผ "ํฌ์žฅ"์„ ํ†ตํ•ฉํ•œ "๋ฐฐ์†ก ๋ฐ ํฌ์žฅ" +- ๊ฐ ์ƒํ’ˆ์˜ ์›๋ณธ ๋ฆฌ๋ทฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ aspect๋ณ„ ๊ธ์ •/๋ถ€์ • ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ์š”์•ฝํ•˜๊ณ , + ๊ฐ aspect๋ณ„ ๊ณ ์œ  ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜๋ฅผ ์‚ฐ์ถœํ•˜์—ฌ ์ตœ์ข… CSV ํŒŒ์ผ๋กœ ์ €์žฅํ•œ๋‹ค. +""" + +import os +import sys +import time +import json +import requests +import pandas as pd +from dotenv import load_dotenv +from prompt.prompt_loader import load_prompt, load_fewshot +import re + +def load_data(file_path): + df = pd.read_csv(file_path) + print("๋ฐ์ดํ„ฐ ๋กœ๋“œ:", file_path) + return df + +def expand_inference_data(df, json_column="unsloth_deepseek_32b"): + expanded = [] + for idx, row in df.iterrows(): + raw_value = row[json_column] + + # ๋งŒ์•ฝ raw_value๊ฐ€ ๋ฌธ์ž์—ด์ด๋ฉด json.loads()๋ฅผ ์‚ฌ์šฉ, ์ด๋ฏธ ๋ฆฌ์ŠคํŠธ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + if isinstance(raw_value, str): + try: + parsed = json.loads(raw_value) + except json.JSONDecodeError: + print(f"JSON ํŒŒ์‹ฑ ์—๋Ÿฌ, review-ID: {row.get('review-ID', 'N/A')}") + continue + elif isinstance(raw_value, list): + parsed = raw_value + else: + # ๊ทธ ์™ธ ํƒ€์ž…์ธ ๊ฒฝ์šฐ ๋ฌด์‹œ + continue + + if isinstance(parsed, list): + for item in parsed: + new_row = row.copy() + new_row["aspect"] = item.get("์†์„ฑ", None) + new_row["opinion"] = item.get("ํ‰๊ฐ€", None) + new_row["sentiment"] = item.get("๊ฐ์ •", None) + expanded.append(new_row) + expanded_df = pd.DataFrame(expanded) + expanded_df.reset_index(drop=True, inplace=True) + expanded_df.ffill(inplace=True) + return expanded_df + +def filter_invalid_value(raw_value): + """ + unsloth_deepseek_32b ์นผ๋Ÿผ์˜ ํ•œ ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„, + - float(NaN) ๋˜๋Š” "[]" ์ธ ๊ฒฝ์šฐ None ๋ฐ˜ํ™˜ + - ์ •์ƒ์ ์ธ JSON ๋ฌธ์ž์—ด์ด๋ฉด ํŒŒ์‹ฑํ•ด์„œ ๋ฐ˜ํ™˜, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด None ๋ฐ˜ํ™˜ + """ + if isinstance(raw_value, float) or (isinstance(raw_value, str) and raw_value.strip() == "[]"): + return None + try: + parsed = json.loads(raw_value) + if isinstance(parsed, list): + return parsed + else: + return None + except json.JSONDecodeError: + return None + +def load_and_prepare_data(config): + train_data_path = os.path.join(config["paths"]["inference_dir"], config["inference_data"]) + df_infer = load_data(train_data_path) + df_infer["unsloth_deepseek_32b"] = df_infer["unsloth_deepseek_32b"].apply(filter_invalid_value) + df_infer = df_infer.dropna(subset=["unsloth_deepseek_32b"]) + aste_df = expand_inference_data(df_infer, "unsloth_deepseek_32b") + # ํ•„์š” ์—†๋Š” ์—ด ์ œ๊ฑฐ + cols_to_drop = ['aste_hcx', 'aste_gpt', 'aste_golden_label'] + aste_df.drop(columns=cols_to_drop, errors='ignore', inplace=True) + print(f"๋ฆฌ๋ทฐ Opinion ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {aste_df.shape[0]}") + # FILTER_KEYWORDS = "๋ง›|์ข‹" + # aste_df = aste_df[~aste_df["opinion"].str.contains(FILTER_KEYWORDS)] + # print(f"ํ•„ํ„ฐ๋ง ํ›„ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ: {aste_df.shape[0]}") + return aste_df + +def get_prompt_and_fewshot(aspect: str, sentiment: str): + """ + aspect์™€ sentiment์— ๋”ฐ๋ฅธ ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. + ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋Š” prompt ํด๋” ๋‚ด์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ๊ด€๋ฆฌ๋œ๋‹ค. + """ + if sentiment == "๊ธ์ •": + prompt = load_prompt(prompt_filename="positive_prompt.txt", + prompt_dir="./prompt/review_summarization/") + fewshot = load_fewshot(fewshot_filename="positive_fewshot.json", + prompt_dir="./prompt/review_summarization/") + else: + prompt = load_prompt(prompt_filename="negative_prompt.txt", + prompt_dir="./prompt/review_summarization/") + fewshot = load_fewshot(fewshot_filename="negative_fewshot.json", + prompt_dir="./prompt/review_summarization/") + return prompt, fewshot + +def inference(query: str, sentiment: str, aspect: str) -> str: + load_dotenv(os.path.expanduser("~/.env")) + AUTHORIZATION = os.getenv("AUTHORIZATION") + X_NCP_CLOVASTUDIO_REQUEST_ID = os.getenv("X_NCP_CLOVASTUDIO_REQUEST_ID") + if not AUTHORIZATION or not X_NCP_CLOVASTUDIO_REQUEST_ID: + raise ValueError("ํ•„์ˆ˜ API ์ธ์ฆ ์ •๋ณด๊ฐ€ .env์— ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + headers = { + 'Authorization': AUTHORIZATION, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': X_NCP_CLOVASTUDIO_REQUEST_ID, + 'Content-Type': 'application/json; charset=utf-8', + } + prompt, fewshot = get_prompt_and_fewshot(aspect, sentiment) + # query๊ฐ€ ๋ฌธ์ž์—ด์ธ๋ฐ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ์˜ ํ‘œํ˜„์ด๋ฉด join + if query.startswith("[") and query.endswith("]"): + try: + import ast + q_list = ast.literal_eval(query) + if isinstance(q_list, list): + query = " ".join(q_list) + except Exception as e: + print("Query parsing error:", e) + + messages = [{"role": "system", "content": prompt}] + for example in fewshot: + # ๋งŒ์•ฝ fewshot์˜ query๊ฐ€ ๋ฆฌ์ŠคํŠธ๋ฉด join + query_text = " ".join(example["query"]) if isinstance(example["query"], list) else example["query"] + messages.append({"role": "user", "content": query_text}) + messages.append({"role": "assistant", "content": example["answer"]}) + messages.append({"role": "user", "content": query}) + + request_data = { + 'messages': messages, + 'topP': 0.8, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.5, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': False, + 'seed': 42 + } + try: + response = requests.post( + "https://clovastudio.stream.ntruss.com/testapp/v1/chat-completions/HCX-003", + headers=headers, json=request_data + ) + response.raise_for_status() + response_json = response.json() + if response_json.get("status", {}).get("code") == "20000": + output_text = response_json["result"]["message"]["content"] + return output_text + else: + return f"API Error: {response_json.get('status', {}).get('message')}" + except requests.exceptions.RequestException as e: + return f"Request Error: {e}" + +def robust_inference(query: str, sentiment: str, aspect: str, retry_delay: int = 2) -> str: + while True: + result = inference(query, sentiment, aspect) + if not (result.startswith("API Error") or result.startswith("Request Error")): + print(result) + return result + print("API ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋‹ค์‹œ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค...") + time.sleep(retry_delay) + +def summarize_opinions_with_original(reviews: list, sentiment: str, aspect: str) -> tuple: + unique_reviews = list(set(reviews)) + sample_reviews = unique_reviews[:20] + if not sample_reviews: + return "์—†์Šต๋‹ˆ๋‹ค.", "์—†์Šต๋‹ˆ๋‹ค." + reviews_str = str(sample_reviews) + summary = robust_inference(reviews_str, sentiment, aspect) + summary = summary.strip()[1:-1] if summary.startswith('"') and summary.endswith('"') else summary + return summary, reviews_str + +def process_product(product_id: str, aste_df: pd.DataFrame) -> dict: + SENTIMENT_POSITIVE = "๊ธ์ •" + SENTIMENT_NEGATIVE = "๋ถ€์ •" + product_reviews = aste_df[aste_df["review-ID"].str.contains(product_id)] + product_name = product_reviews["name"].dropna().unique()[0] + product_dict = { + "ID": product_id, + "์ƒํ’ˆ๋ช…": product_name, + } + # ๋ง› ๋‹จ๋… ์ฒ˜๋ฆฌ + pos_reviews_m = product_reviews[(product_reviews["aspect"] == "๋ง›") & (product_reviews["sentiment"] == SENTIMENT_POSITIVE)]["review"].tolist() + neg_reviews_m = product_reviews[(product_reviews["aspect"] == "๋ง›") & (product_reviews["sentiment"] != SENTIMENT_POSITIVE)]["review"].tolist() + summary_pos_m, _ = summarize_opinions_with_original(pos_reviews_m, SENTIMENT_POSITIVE, "๋ง›") + summary_neg_m, _ = summarize_opinions_with_original(neg_reviews_m, SENTIMENT_NEGATIVE, "๋ง›") + product_dict["๋ง›-๊ธ์ •"] = summary_pos_m + product_dict["๋ง›-๋ถ€์ •"] = summary_neg_m + + # ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ ํ†ตํ•ฉ ์ฒ˜๋ฆฌ: ๋ฐฐ์†ก๊ณผ ํฌ์žฅ ๋‘˜ ๋‹ค ํฌํ•จ + pos_reviews_dp = product_reviews[((product_reviews["aspect"] == "๋ฐฐ์†ก") | (product_reviews["aspect"] == "ํฌ์žฅ")) & + (product_reviews["sentiment"] == SENTIMENT_POSITIVE)]["review"].tolist() + neg_reviews_dp = product_reviews[((product_reviews["aspect"] == "๋ฐฐ์†ก") | (product_reviews["aspect"] == "ํฌ์žฅ")) & + (product_reviews["sentiment"] != SENTIMENT_POSITIVE)]["review"].tolist() + summary_pos_dp, _ = summarize_opinions_with_original(pos_reviews_dp, SENTIMENT_POSITIVE, "๋ฐฐ์†ก ๋ฐ ํฌ์žฅ") + summary_neg_dp, _ = summarize_opinions_with_original(neg_reviews_dp, SENTIMENT_NEGATIVE, "๋ฐฐ์†ก ๋ฐ ํฌ์žฅ") + product_dict["๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๊ธ์ •"] = summary_pos_dp + product_dict["๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๋ถ€์ •"] = summary_neg_dp + + return product_dict + +def update_summary_counts(summary_df: pd.DataFrame, aste_df: pd.DataFrame) -> pd.DataFrame: + summary_df["num ๋ง›-๊ธ์ •"] = None + summary_df["num ๋ง›-๋ถ€์ •"] = None + summary_df["num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๊ธ์ •"] = None + summary_df["num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๋ถ€์ •"] = None + + for idx, row in summary_df.iterrows(): + product_id = row["ID"] + product_reviews = aste_df[aste_df["review-ID"].str.contains(product_id)] + num_m_pos = len(product_reviews[(product_reviews["aspect"] == "๋ง›") & (product_reviews["sentiment"] == "๊ธ์ •")]["review"].unique()) + num_m_neg = len(product_reviews[(product_reviews["aspect"] == "๋ง›") & (product_reviews["sentiment"] != "๊ธ์ •")]["review"].unique()) + num_dp_pos = len(product_reviews[((product_reviews["aspect"] == "๋ฐฐ์†ก") | (product_reviews["aspect"] == "ํฌ์žฅ")) & (product_reviews["sentiment"] == "๊ธ์ •")]["review"].unique()) + num_dp_neg = len(product_reviews[((product_reviews["aspect"] == "๋ฐฐ์†ก") | (product_reviews["aspect"] == "ํฌ์žฅ")) & (product_reviews["sentiment"] != "๊ธ์ •")]["review"].unique()) + + summary_df.at[idx, "num ๋ง›-๊ธ์ •"] = num_m_pos + summary_df.at[idx, "num ๋ง›-๋ถ€์ •"] = num_m_neg + summary_df.at[idx, "num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๊ธ์ •"] = num_dp_pos + summary_df.at[idx, "num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๋ถ€์ •"] = num_dp_neg + + return summary_df + +def extract_product_id(review_id): + match = re.match(r"(emart-\d+)-\d+", review_id) + return match.group(1) if match else review_id # ๋งค์นญ ์‹คํŒจ ์‹œ ์›๋ž˜ ๊ฐ’ ๋ฐ˜ํ™˜ + +def load_and_prepare_data(config): + train_data_path = os.path.join(config["paths"]["inference_dir"], config["inference_data"]) + df_infer = load_data(train_data_path) + df_infer["unsloth_deepseek_32b"] = df_infer["unsloth_deepseek_32b"].apply(filter_invalid_value) + df_infer = df_infer.dropna(subset=["unsloth_deepseek_32b"]) + aste_df = expand_inference_data(df_infer, "unsloth_deepseek_32b") + cols_to_drop = ['aste_hcx', 'aste_gpt', 'aste_golden_label'] + aste_df.drop(columns=cols_to_drop, errors='ignore', inplace=True) + print(f"๋ฆฌ๋ทฐ Opinion ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {aste_df.shape[0]}") + print(f"ํ•„ํ„ฐ๋ง ํ›„ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ: {aste_df.shape[0]}") + return aste_df + + +def run_review_summarization(config): + print("\n[๋ฆฌ๋ทฐ ์š”์•ฝ ์ถ”์ถœ ์‹œ์ž‘]\n") + aste_df = load_and_prepare_data(config) + product_ids = list({extract_product_id(item) for item in aste_df["review-ID"].tolist()}) + print(f"์ฒ˜๋ฆฌํ•  ์ƒํ’ˆ ์ˆ˜: {len(product_ids)}") + summary_list = [] + for prod_id in product_ids: + prod_summary = process_product(prod_id, aste_df) + summary_list.append(prod_summary) + summary_df = pd.DataFrame(summary_list) + summary_df = update_summary_counts(summary_df, aste_df) + final_columns = ["ID", "์ƒํ’ˆ๋ช…", "๋ง›-๊ธ์ •", "๋ง›-๋ถ€์ •", "๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๊ธ์ •", "๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๋ถ€์ •", + "num ๋ง›-๊ธ์ •", "num ๋ง›-๋ถ€์ •", "num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๊ธ์ •", "num ๋ฐฐ์†ก ๋ฐ ํฌ์žฅ-๋ถ€์ •"] + summary_df = summary_df[final_columns] + output_file = os.path.join(config["paths"]["final_outputs_dir"], "summarization.csv") + os.makedirs(os.path.dirname(output_file), exist_ok=True) + summary_df.to_csv(output_file, index=False) + print(f"์ตœ์ข… ์š”์•ฝ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {output_file}") + print("\n[๋ฆฌ๋ทฐ ์š”์•ฝ ์ถ”์ถœ ์™„๋ฃŒ]\n") + return summary_df + + +if __name__ == "__main__": + run_review_summarization({ + "paths": { + "inference_dir": "./data/aste/inference", + "preprocessed_dir": "./data/preprocessed", + "final_outputs_dir": "../final_outputs" + }, + "inference_data": "inferenced_reviews_snacks_meals_2.csv" + }) diff --git a/models/review/src/review_pipeline/visualization.py b/models/review/src/review_pipeline/visualization.py new file mode 100644 index 0000000..94a712d --- /dev/null +++ b/models/review/src/review_pipeline/visualization.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[ํด๋Ÿฌ์Šคํ„ฐ๋ง ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” ๋ฐ ์ •๋Ÿ‰์  ํ‰๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ] +- ์ž…๋ ฅ CSV ํŒŒ์ผ ๋กœ๋ถ€ํ„ฐ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๋ณ„๋กœ ์ƒํ’ˆ์„ ์žฌ์ •๋ ฌํ•˜์—ฌ ์ตœ์ข… ์ถ”์ฒœ CSV ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค. +- ์ตœ์ข… ์ถœ๋ ฅ CSV ํŒŒ์ผ์€ ๋‹ค์Œ ์—ด๋กœ ๊ตฌ์„ฑ๋œ๋‹ค: + ์นดํ…Œ๊ณ ๋ฆฌ, ํ‚ค์›Œ๋“œ, ID, ์ƒํ’ˆ๋ช…, opinion ๊ฐœ์ˆ˜ +- ๋ณธ ํŒŒ์ดํ”„๋ผ์ธ์€ config๋ฅผ ํ™œ์šฉํ•˜๊ณ , prompt ํด๋”์˜ ํ”„๋กฌํ”„ํŠธ ๋ฐ few-shot ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. +- run_keyword_recommendation() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ์„ ์‹คํ–‰ํ•œ๋‹ค. +""" + +import os, sys +import re +import json +import time +import requests +import pandas as pd +import numpy as np +import yaml + +project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +if project_root not in sys.path: + sys.path.insert(0, project_root) + +from utils.utils import load_data, expand_inference_data, sentenceBERT_embeddings, umap_reduce_embeddings, agglomerative_clustering, visualize_clustering, evaluate_clustering + +######################################################### +# ๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ ๋ฐ ํ™•์žฅ ๊ด€๋ จ ํ•จ์ˆ˜ +######################################################### + +def filter_invalid_value(raw_value): + """ + unsloth_deepseek_32b ์นผ๋Ÿผ์˜ ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„, + - float(NaN) ๋˜๋Š” "[]"์ธ ๊ฒฝ์šฐ None ๋ฐ˜ํ™˜ + - ์ •์ƒ์ ์ธ JSON ๋ฌธ์ž์—ด์ด๋ฉด ํŒŒ์‹ฑ ํ›„ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด None ๋ฐ˜ํ™˜ + """ + if isinstance(raw_value, float) or (isinstance(raw_value, str) and raw_value.strip() == "[]"): + return None + try: + parsed = json.loads(raw_value) + if isinstance(parsed, list): + return parsed + else: + return None + except json.JSONDecodeError: + return None + +def load_and_prepare_data(config): + """ + config์— ๋ช…์‹œ๋œ ๊ฒฝ๋กœ์™€ ํŒŒ์ผ๋ช…์„ ํ™œ์šฉํ•˜์—ฌ ์ž…๋ ฅ CSV ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๊ณ , + unsloth_deepseek_32b ์นผ๋Ÿผ์˜ ๊ฐ’์„ ํŒŒ์‹ฑํ•œ ํ›„ ํ™•์žฅํ•œ๋‹ค. + ๋ถˆํ•„์š”ํ•œ ์—ด์€ ์‚ญ์ œํ•œ๋‹ค. + """ + train_data_path = os.path.join(config["paths"]["inference_dir"], config["inference_data"]) + df_infer = load_data(train_data_path) + df_infer["unsloth_deepseek_32b"] = df_infer["unsloth_deepseek_32b"].apply(filter_invalid_value) + df_infer = df_infer.dropna(subset=["unsloth_deepseek_32b"]) + aste_df = expand_inference_data(df_infer, "unsloth_deepseek_32b") + cols_to_drop = ['aste_hcx', 'aste_gpt', 'aste_golden_label'] + aste_df.drop(columns=cols_to_drop, errors='ignore', inplace=True) + print(f"๋ฆฌ๋ทฐ Opinion ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {aste_df.shape[0]}") + return aste_df + + +######################################################### +# ์ตœ์ข… ํ‰๊ฐ€ ์‹คํ–‰ ํ•จ์ˆ˜ +######################################################### + +print("\n[์ถ”์ฒœ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ์žฌ์ •๋ ฌ ์‹œ๊ฐํ™”, ์ •๋Ÿ‰์  ํ‰๊ฐ€]\n") + +# config ํŒŒ์ผ์„ config/config.yaml์—์„œ ๋กœ๋“œ (ํŒŒ์ผ ์œ„์น˜: ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ/config/config.yaml) +config_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "..", "..", "config", "config.yaml" +) + +with open(config_path, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + +# 1. ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ +aste_df = load_and_prepare_data(config) + +# 2. ๊ธ์ • ์˜๊ฒฌ๋งŒ ์„ ํƒ (์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋Š” ๊ธ์ • ๋ฆฌ๋ทฐ ๊ธฐ๋ฐ˜) +infer_pos = aste_df[aste_df["sentiment"] == "๊ธ์ •"] +infer_pos.loc[:, 'category'] = infer_pos['category'].replace({'์•„์ด๊ฐ„์‹': '๋ผ๋ฉด/๊ฐ„ํŽธ์‹'}) + +category_map = { + "๊ณผ์ž/๋น™๊ณผ": "snacks", + "๋ผ๋ฉด/๊ฐ„ํŽธ์‹": "meals" +} + +infer_pos["category"] = infer_pos["category"].map(category_map).fillna(infer_pos["category"]) + +# ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ DataFrame ๋ถ„ํ•  +category_dfs = {category: df for category, df in infer_pos.groupby("category")} + +for category, df_cat in category_dfs.items(): + # 3. ๋ฆฌ๋ทฐ ํ…์ŠคํŠธ ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ (opinion ์—ด ์‚ฌ์šฉ) + embedding_file = os.path.join(config["paths"]["embedding_dir"], f"deepseek_inference_{category}.npy") + embedding_matrix = sentenceBERT_embeddings(embedding_file, df=df_cat, column="opinion") + + # 4. UMAP ์ฐจ์› ์ถ•์†Œ + reduced_embeddings = umap_reduce_embeddings(embedding_matrix, n_components=256) + + # 5. ํด๋Ÿฌ์Šคํ„ฐ๋ง (Agglomerative Clustering ์‚ฌ์šฉ, ์ž„๊ณ„๊ฐ’ ์กฐ์ •) + cluster_labels = agglomerative_clustering(reduced_embeddings, distance_threshold=21.5) + df_cat['cluster_label'] = cluster_labels + + # 6. ํด๋Ÿฌ์Šคํ„ฐ ์‹œ๊ฐํ™” + visualize_clustering(reduced_embeddings, cluster_labels, config, category) + + # 7. ํ‰๊ฐ€ Metric + evaluate_clustering(reduced_embeddings, cluster_labels, config, category) diff --git a/models/review/src/sft_pipeline/__init__.py b/models/review/src/sft_pipeline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/review/src/sft_pipeline/qwen_deepseek_14b_finetuning.py b/models/review/src/sft_pipeline/qwen_deepseek_14b_finetuning.py new file mode 100644 index 0000000..c518c9f --- /dev/null +++ b/models/review/src/sft_pipeline/qwen_deepseek_14b_finetuning.py @@ -0,0 +1,137 @@ +import torch +import pandas as pd +from datasets import Dataset +from peft import get_peft_model, LoraConfig, TaskType +from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, TrainerCallback, TrainingArguments, Trainer + + +class Review_DeepSeekTrainer: + def __init__(self, model_path, train_path, eval_path, output_dir): + self.model_path = model_path + self.train_path = train_path, + self.eval_path = eval_path + self.output_dir = output_dir + self.PROMPT = """๋‹น์‹ ์€ ์‹ํ’ˆ ๋ฆฌ๋ทฐ์˜ ๊ฐ์„ฑ ๋ถ„์„ ๋ฐ ํ‰๊ฐ€ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ๋ทฐ์—์„œ ์†์„ฑ๊ณผ ํ‰๊ฐ€, ๊ฐ์„ฑ์„ ์ถ”์ถœํ•˜์„ธ์š”. + +### ์ž‘์—… ๋ชฉํ‘œ: +1. ์ž…๋ ฅ์œผ๋กœ ์ฃผ์–ด์ง€๋Š” ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•˜์„ธ์š”. +2. JSON ํ˜•์‹์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. + ```json + [ + {{"์†์„ฑ": "<์†์„ฑ๋ช…1>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ1>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + {{"์†์„ฑ": "<์†์„ฑ๋ช…2>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ2>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + ... + ] + ``` + +์†์„ฑ์€ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค: ["์ƒํ’ˆ", "๋ฐฐ์†ก", "๊ฐ€๊ฒฉ", "๋ง›", "์‹ ์„ ๋„", "์–‘", "ํฌ์žฅ"]. +๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์†์„ฑ์ด ํ•„์š”ํ•˜๋ฉด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +๋ชจ๋“  ์‹ํ’ˆ๋ช…์€ "์ƒํ’ˆ"์œผ๋กœ ํ†ต์ผํ•ฉ๋‹ˆ๋‹ค. + +### ์„ธ๋ถ€ ๊ทœ์น™: +- ๊ฐ์ • ๋ถ„์„ + - ๋ฆฌ๋ทฐ์—์„œ ๊ฐ์ •์ด ๊ธ์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "๊ธ์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ๋ถ€์ •์ ์ธ ํ‘œํ˜„์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ "๊ฐ์ •": "๋ถ€์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€๊ฐ€ ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "์ค‘๋ฆฝ"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + +- ํ‰๊ฐ€ ๋ฌธ๊ตฌ ์ •์ œ + - ๋ฆฌ๋ทฐ์—์„œ ๋‚˜ํƒ€๋‚œ ์ฃผ์š” ํ‰๊ฐ€๋ฅผ ๊ฐ„๊ฒฐํ•œ ๋ฌธ์žฅ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + - ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„์€ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€ ๋ฌธ๊ตฌ๋Š” '~๋‹ค.'๋กœ ๋๋‚˜๋Š” ํ˜„์žฌํ˜•, ํ‰์„œ๋ฌธ์œผ๋กœ ๋‹ต๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '์ข‹์Šต๋‹ˆ๋‹ค.' ๊ฐ€ ์•„๋‹Œ '์ข‹๋‹ค.' ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + +- ์˜ˆ์™ธ ์‚ฌํ•ญ + - ์ƒํ’ˆ ์‚ฌ์šฉ ํ›„๊ธฐ๊ฐ€ ์•„๋‹Œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์˜ˆ์ƒ์ด๋‚˜ ๊ธฐ๋Œ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ„๋ฆฌํ•˜์—ฌ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค. + - ๋ณตํ•ฉ์ ์ธ ํ‰๊ฐ€๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ๊ฐ JSON ํ•ญ๋ชฉ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '๋ฐฐ์†ก์ด ์•ˆ์ „ํ•˜๊ณ  ๋นจ๋ž์–ด์š”'์˜ ๊ฒฝ์šฐ '์•ˆ์ „ํ•˜๋‹ค.' ์™€ '๋น ๋ฅด๋‹ค.' ๋‘ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + +### ์ž…๋ ฅ: +{review} +""" + self.tokenizer = AutoTokenizer.from_pretrained(model_path) + self.model = self.load_model() + + def load_model(self): + bnb_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_compute_dtype=torch.float32 + ) + + model = AutoModelForCausalLM.from_pretrained( + self.model_path, + quantization_config=bnb_config, + device_map="auto" + ) + + lora_config = LoraConfig( + target_modules=['q_proj', 'k_proj', 'v_proj', 'o_proj', 'gate_proj', 'up_proj', 'down_proj'], + r=8, + lora_alpha=16, + lora_dropout=0.1, + task_type=TaskType.CAUSAL_LM + ) + + return get_peft_model(model, lora_config) + + def load_datasets(self): + train_data_df = pd.read_csv(self.train_path) + eval_data_df = pd.read_csv(self.eval_path) + + train_dataset = [{"prompt": self.PROMPT.format(review=txt), "completion": think} + for txt, think in zip(train_data_df["processed"], train_data_df["GPT-4o-Response"])] + eval_dataset = [{"prompt": self.PROMPT.format(review=txt), "completion": answer} + for txt, answer in zip(eval_data_df["processed"], eval_data_df["GPT-4o-Response"])] + + return Dataset.from_list(train_dataset), Dataset.from_list(eval_dataset) + + def tokenize_func(self, dataset): + combined_texts = [f"{prompt}\n{completion}" for prompt, completion in zip(dataset["prompt"], dataset["completion"])] + tokenized = self.tokenizer(combined_texts, truncation=True, max_length=800, padding="max_length") + tokenized["labels"] = tokenized["input_ids"].copy() + return tokenized + + def train(self): + tokenized_train_dataset = self.train_datset.map(self.tokenize_func, batched=True) + tokenized_eval_dataset = self.eval_datset.map(self.tokenize_func, batched=True) + + training_args = TrainingArguments( + output_dir=self.output_dir, + num_train_epochs=5, + per_device_train_batch_size=1, + gradient_accumulation_steps=16, + fp16=True, + logging_steps=10, + save_steps=100, + per_device_eval_batch_size=1, + evaluation_strategy="steps", + eval_strategy="steps", + eval_steps=10, + learning_rate=1e-5, + logging_dir="./logs", + run_name=self.output_dir, + ) + + class MoveToCPUTensorCallback(TrainerCallback): + def on_step_end(self, args, state, control, **kwargs): + torch.cuda.empty_cache() + torch.cuda.ipc_collect() + + trainer = Trainer( + model=self.model, + args=training_args, + train_dataset=tokenized_train_dataset, + eval_dataset=tokenized_eval_dataset, + callbacks=[MoveToCPUTensorCallback()] + ) + + trainer.train() + + self.model.save_pretrained(self.output_dir) + self.tokenizer.save_pretrained(self.output_dir) + print(f"Model saved to {self.output_dir}") + +if __name__ == "__main__": + trainer = Review_DeepSeekTrainer( + model_path="deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", + train_path="./data/aste/train/train_data.csv", + eval_path="./data/aste/eval/aste_annotation_100_golden_label.csv", + output_dir="./deepseek_14b_finetune" + ) diff --git a/models/review/src/sft_pipeline/qwen_deepseek_32b_finetuning.py b/models/review/src/sft_pipeline/qwen_deepseek_32b_finetuning.py new file mode 100644 index 0000000..a452de8 --- /dev/null +++ b/models/review/src/sft_pipeline/qwen_deepseek_32b_finetuning.py @@ -0,0 +1,217 @@ +from unsloth import FastLanguageModel + + +def set_model_size(parameters: str) -> str: + """๋ชจ๋ธ ํฌ๊ธฐ์— ๋”ฐ๋ฅธ ๋ชจ๋ธ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.""" + model_map = { + "14B": "unsloth/DeepSeek-R1-Distill-Qwen-14B-bnb-4bit", + "32B": "unsloth/DeepSeek-R1-Distill-Qwen-32B-bnb-4bit" + } + if parameters in model_map: + print(f"Setting model size to {parameters}") + return model_map[parameters] + else: + raise ValueError("Invalid model size. Choose '14B' or '32B'.") + +def load_model(model_size: str = "32B"): + """๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.""" + model_name = set_model_size(model_size) + model, tokenizer = FastLanguageModel.from_pretrained( + model_name=model_name, + max_seq_length=2048, + dtype=None, + load_in_4bit=True, + temperature=0.6 + ) + FastLanguageModel.for_inference(model) + return model, tokenizer + +PROMPT_TEMPLATE = """๋‹น์‹ ์€ ์‹ํ’ˆ ๋ฆฌ๋ทฐ์˜ ๊ฐ์„ฑ ๋ถ„์„ ๋ฐ ํ‰๊ฐ€ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ๋ทฐ์—์„œ ์†์„ฑ๊ณผ ํ‰๊ฐ€, ๊ฐ์„ฑ์„ ์ถ”์ถœํ•˜์„ธ์š”. + +### ์ž‘์—… ๋ชฉํ‘œ: +1. ์ž…๋ ฅ์œผ๋กœ ์ฃผ์–ด์ง€๋Š” ์‹ํ’ˆ ๋ฆฌ๋ทฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•˜์„ธ์š”. +2. JSON ํ˜•์‹์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. + ```json + [ + {{"์†์„ฑ": "<์†์„ฑ๋ช…1>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ1>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + {{"์†์„ฑ": "<์†์„ฑ๋ช…2>", "ํ‰๊ฐ€": "<ํ‰๊ฐ€ ๋‚ด์šฉ2>", "๊ฐ์ •": "<๊ธ์ •/๋ถ€์ •/์ค‘๋ฆฝ>"}}, + ... + ] + ``` + +์†์„ฑ์€ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค: ["์ƒํ’ˆ", "๋ฐฐ์†ก", "๊ฐ€๊ฒฉ", "๋ง›", "์‹ ์„ ๋„", "์–‘", "ํฌ์žฅ"]. +๋งŒ์•ฝ ์ƒˆ๋กœ์šด ์†์„ฑ์ด ํ•„์š”ํ•˜๋ฉด ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +๋ชจ๋“  ์‹ํ’ˆ๋ช…์€ "์ƒํ’ˆ"์œผ๋กœ ํ†ต์ผํ•ฉ๋‹ˆ๋‹ค. + +### ์„ธ๋ถ€ ๊ทœ์น™: +- ๊ฐ์ • ๋ถ„์„ + - ๋ฆฌ๋ทฐ์—์„œ ๊ฐ์ •์ด ๊ธ์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "๊ธ์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ๋ถ€์ •์ ์ธ ํ‘œํ˜„์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ "๊ฐ์ •": "๋ถ€์ •"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€๊ฐ€ ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ •์ ์ธ ๊ฒฝ์šฐ "๊ฐ์ •": "์ค‘๋ฆฝ"์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + +- ํ‰๊ฐ€ ๋ฌธ๊ตฌ ์ •์ œ + - ๋ฆฌ๋ทฐ์—์„œ ๋‚˜ํƒ€๋‚œ ์ฃผ์š” ํ‰๊ฐ€๋ฅผ ๊ฐ„๊ฒฐํ•œ ๋ฌธ์žฅ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + - ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„์€ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + - ํ‰๊ฐ€ ๋ฌธ๊ตฌ๋Š” '~๋‹ค.'๋กœ ๋๋‚˜๋Š” ํ˜„์žฌํ˜•, ํ‰์„œ๋ฌธ์œผ๋กœ ๋‹ต๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '์ข‹์Šต๋‹ˆ๋‹ค.' ๊ฐ€ ์•„๋‹Œ '์ข‹๋‹ค.' ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + +- ์˜ˆ์™ธ ์‚ฌํ•ญ + - ์ƒํ’ˆ ์‚ฌ์šฉ ํ›„๊ธฐ๊ฐ€ ์•„๋‹Œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์˜ˆ์ƒ์ด๋‚˜ ๊ธฐ๋Œ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ„๋ฆฌํ•˜์—ฌ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค. + - ๋ณตํ•ฉ์ ์ธ ํ‰๊ฐ€๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ๊ฐ JSON ํ•ญ๋ชฉ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, '๋ฐฐ์†ก์ด ์•ˆ์ „ํ•˜๊ณ  ๋นจ๋ž์–ด์š”'์˜ ๊ฒฝ์šฐ '์•ˆ์ „ํ•˜๋‹ค.' ์™€ '๋น ๋ฅด๋‹ค.' ๋‘ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + +### ์ž…๋ ฅ: +{review} + +""" + +model, tokenizer = load_model("32B") + +model = FastLanguageModel.get_peft_model( + model, + r = 16, # Choose any number > 0 ! Suggested 8, 16, 32, 64, 128 + target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", + "gate_proj", "up_proj", "down_proj",], + lora_alpha = 16, + lora_dropout = 0, # Supports any, but = 0 is optimized + bias = "none", # Supports any, but = "none" is optimized + # [NEW] "unsloth" uses 30% less VRAM, fits 2x larger batch sizes! + use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context + random_state = 3407, + use_rslora = False, # We support rank stabilized LoRA + loftq_config = None, # And LoftQ +) + +import json +import re +import pandas as pd +from torch.utils.data import Dataset + +EOS_TOKEN = tokenizer.eos_token + +class ASTEDataset(Dataset): + def __init__(self, csv_file, encoding='utf-8'): + """ + csv_file: CSV ํŒŒ์ผ ๊ฒฝ๋กœ + encoding: CSV ํŒŒ์ผ ์ธ์ฝ”๋”ฉ (๊ธฐ๋ณธ๊ฐ’: 'utf-8') + """ + # CSV ํŒŒ์ผ์„ pandas DataFrame์œผ๋กœ ๋กœ๋“œ + self.data = pd.read_csv(csv_file, encoding=encoding) + + self.data['GPT-4o-Answer'] = self.data['GPT-4o-Answer'].apply( + lambda x: re.sub(r'""', '"', x) + ) + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + # DataFrame์—์„œ ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ row๋ฅผ ๊ฐ€์ ธ์˜ด + row = self.data.iloc[idx] + + # ๋ฆฌ๋ทฐ ํ…์ŠคํŠธ๋ฅผ prompt ํ…œํ”Œ๋ฆฟ์— ๋งž๊ฒŒ ํฌ๋งทํŒ… + prompt_text = row['๋ฆฌ๋ทฐ'] + prompt = PROMPT_TEMPLATE.format(review=prompt_text) + + label_json_str = row['GPT-4o-Answer'] + try: + label_obj = json.loads(label_json_str) + except json.JSONDecodeError: + # JSON ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜ + label_obj = [] + + cot = row["GPT-4o-Reasoning"] + "\n" + + # JSON ๋ธ”๋ก ํ˜•ํƒœ๋กœ ๊ฐ€๊ณตํ•˜์—ฌ ์ถœ๋ ฅ + label_text = f'```json\n{json.dumps(label_obj, ensure_ascii=False, indent=4)}\n```' + + text_all = prompt + cot + label_text + EOS_TOKEN + print(text_all) + + return { + 'instruction': prompt, + 'output': label_text, + 'text': text_all, + } + +from ast import literal_eval + +def process_aste_example(example): + """ + datasets.map()์—์„œ ๊ฐ ๋ฐฐ์น˜์— ์ ์šฉ๋  ํ•จ์ˆ˜ + ์ž…๋ ฅ example์€ dict ํ˜•ํƒœ๋กœ, ํ‚ค๋Š” '๋ฆฌ๋ทฐ', 'aste_golden_label' ๋“ฑ์ด๊ณ  ๊ฐ’์€ ๋ฆฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. + """ + instructions = [] + outputs = [] + texts = [] + + # ๊ฐ ๋ฐฐ์น˜์˜ ์ƒ˜ํ”Œ๋“ค์„ ์ˆœํšŒ + for review, cot, aste_label in zip(example['๋ฆฌ๋ทฐ'], example['GPT-4o-Reasoning'], example['GPT-4o-Answer']): + prompt_text = review + prompt = PROMPT_TEMPLATE.format(review=prompt_text) + + # ์ด์ค‘ ๋”ฐ์˜ดํ‘œ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐ JSON ํŒŒ์‹ฑ ์‹œ๋„ + try: + label_obj = json.loads(aste_label) # JSON ๋ณ€ํ™˜ ์‹œ๋„ + except json.JSONDecodeError: + try: + label_obj = literal_eval(aste_label) + except Exception: + label_obj = [] # ๋ณ€ํ™˜ ์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ + + # JSON ๋ฌธ์ž์—ด์„ ๊ฐ€๊ณต + label_text = f'```json\n{json.dumps(label_obj, ensure_ascii=False, indent=4)}\n```' + text_all = prompt + cot + '\n\n' + label_text + EOS_TOKEN + + instructions.append(prompt) + outputs.append(label_text) + texts.append(text_all) + + + # ๊ฐ ํ‚ค๋ณ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” dict๋กœ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ + return { + 'instruction': instructions, + 'output': outputs, + 'text': texts, + } + +from datasets import load_dataset + +dataset = load_dataset("csv", data_files="train_gpt_splitted.csv", split="train") +dataset = dataset.map(process_aste_example, batched=True, ) + +print("---") +print("dataset:", dataset[1]) +print("---") +print("dataset[1]['text']:", dataset[1]["text"]) + +from trl import SFTTrainer +from transformers import TrainingArguments +from unsloth import is_bfloat16_supported + +trainer = SFTTrainer( + model = model, + tokenizer = tokenizer, + train_dataset = dataset, + dataset_text_field = "text", + max_seq_length = 2048, + dataset_num_proc = 2, + packing = False, # Can make training 5x faster for short sequences. + args = TrainingArguments( + per_device_train_batch_size = 2, + gradient_accumulation_steps = 4, + warmup_steps = 5, + num_train_epochs = 3, # Set this for 1 full training run. + # max_steps = 60, + learning_rate = 2e-4, + fp16 = not is_bfloat16_supported(), + bf16 = is_bfloat16_supported(), + logging_steps = 1, + optim = "adamw_8bit", + weight_decay = 0.01, + lr_scheduler_type = "linear", + seed = 42, + output_dir = "output_zeroshot", + report_to = "none", # Use this for WandB etc + ), +) + +trainer_stats = trainer.train() diff --git a/models/review/src/sft_pipeline/review_crawling.py b/models/review/src/sft_pipeline/review_crawling.py new file mode 100644 index 0000000..b28bf2d --- /dev/null +++ b/models/review/src/sft_pipeline/review_crawling.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[์ƒํ’ˆ ์ •๋ณด ๋ฐ ๋ฆฌ๋ทฐ ํฌ๋กค๋ง ํŒŒ์ดํ”„๋ผ์ธ] +- ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ์ƒํ’ˆ ์ •๋ณด, ์ƒ์„ธ ์ •๋ณด, ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. +- ์ฃผ์š” ๊ธฐ๋Šฅ: + 1. get_product_urls: ์ง€์ •๋œ ์นดํ…Œ๊ณ ๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ƒํ’ˆ๋ช…๊ณผ URL ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ + 2. get_product_details: ๊ฐ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ + 3. details_to_csv: ์ˆ˜์ง‘ํ•œ ์ •๋ณด๋ฅผ CSV ํŒŒ์ผ๋กœ ์ €์žฅ + 4. get_product_reviews: ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ CSV๋กœ ์ €์žฅ +""" + +import re +import json +import time +import os +import pandas as pd +from tqdm import tqdm +from pprint import pprint +from bs4 import BeautifulSoup +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from webdriver_manager.chrome import ChromeDriverManager + +def get_product_urls(mall_category_url, market="emart", category="์•„์ด๊ฐ„์‹", limit=50): + BASE_URL = "https://shopping.naver.com" + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + all_items = [] + driver.get(mall_category_url) + last_height = driver.execute_script("return document.body.scrollHeight") + while True: + try: + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_3m7zfsGIZR"))) + except Exception as e: + print("ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", e) + soup = BeautifulSoup(driver.page_source, "html.parser") + items_list = soup.find_all("li", class_="_3m7zfsGIZR") + for item in items_list: + source = item.find("a", class_=re.compile(".*_3OaphyWXEP.*")) + if source is None: + continue + name_dict = json.loads(source["data-shp-contents-dtl"]) + all_items.append({ + "name": name_dict[0]["value"], + "url": BASE_URL + source["href"], + "market": market, + "category": category + }) + all_items = [dict(i) for i in {frozenset(item.items()) for item in all_items}] + if len(all_items) >= limit: + break + driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") + time.sleep(5) + new_height = driver.execute_script("return document.body.scrollHeight") + if new_height == last_height: + break + last_height = new_height + driver.quit() + print("์ƒํ’ˆ ์ด ๊ฐœ์ˆ˜:", len(all_items)) + return all_items + +def get_product_details(all_items, limit=50): + from selenium.webdriver.chrome.options import Options # ์ค‘๋ณต import ๋ฐฉ์ง€ + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + for item in tqdm(all_items[:limit], desc="์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ง‘", total=len(all_items[:limit])): + driver.get(item["url"]) + try: + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_1Z00EgoxQ9"))) + except Exception as e: + print("ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", e) + soup = BeautifulSoup(driver.page_source, "html.parser") + try: + thumbnail_img = soup.find("div", class_="_2tT_gkmAOr").find("img")["src"] + item["thumbnail"] = thumbnail_img + except Exception as e: + item["thumbnail"] = None + items_list = soup.find_all("span", class_="_1LY7DqCnwR") + prices = [] + for span in items_list: + try: + prices.append(int(span.get_text().replace(",", ""))) + except Exception: + continue + if prices: + if len(prices) > 1: + item["price"] = { + "before_price": max(prices), + "after_price": min(prices) + } + else: + item["price"] = {"before_price": prices[0]} + else: + item["price"] = {} + try: + strong = soup.find("strong", class_="_2pgHN-ntx6") + star = strong.get_text()[2:] + item["star"] = float(star) + except Exception as e: + item["star"] = None + sources = soup.find_all("div", class_="_1Z00EgoxQ9") + imgs = [] + divs = [] + texts = [] + for s in sources: + imgs = [str(i["src"]) for i in s.find_all("img")] + divs = [div.get_text() for div in s.find_all("div", class_="tmpl_tit_para")] + texts = [p.get_text() for p in s.find_all(["h2", "p", "strong", "b"])] + item["imgs"] = {"num": len(imgs), "urls": imgs} + item["texts"] = {"num": len(texts), "divs": divs, "contents": texts} + try: + item["reviews"] = int(soup.find("span", class_="_3HJHJjSrNK").get_text().replace(",", "")) + except Exception as e: + item["reviews"] = 0 + print("๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ ์ˆ˜์ง‘ ์‹คํŒจ:", item["url"]) + pprint(item) + print("\n" + "=" * 100 + "\n") + driver.quit() + return all_items + +def details_to_csv(all_items): + data_df = pd.DataFrame(columns=["ID", "img-ID", "category", "name", "url", "before_price", "after_price", "star", "thumbnail", "imgs", "texts", "num_reviews"]) + for idx, item in enumerate(all_items[:2]): # ์˜ˆ์ œ: 2๊ฐœ ์ƒํ’ˆ์— ๋Œ€ํ•ด ์ €์žฅ + market = item["market"] + product_df = pd.DataFrame({ + "ID": f"{market}-{str(idx+1)}", + "img-ID": f"{market}-{str(idx+1)}-0", + "category": item["category"], + "name": item["name"], + "url": item["url"], + "before_price": item["price"].get("before_price", None), + "after_price": item["price"].get("after_price", None), + "thumbnail": item.get("thumbnail", None), + "star": item.get("star", None), + "texts": [str(item.get("texts", {}))], + "num_reviews": item.get("reviews", 0) + }) + image_df = pd.DataFrame(columns=["ID", "img-ID", "imgs"]) + for i, img in enumerate(item.get("imgs", {}).get("urls", [])): + image_df.loc[i] = [f"{market}-{str(idx+1)}", f"{market}-{str(idx+1)}-{str(i+1)}", img] + product_df = pd.concat([product_df, image_df], axis=0) + data_df = pd.concat([data_df, product_df], axis=0) + data_df.to_csv("product_details.csv", index=False) + print("์ƒ์„ธ ์ •๋ณด CSV ์ €์žฅ ์™„๋ฃŒ: product_details.csv") + +def get_product_reviews(all_items): + from selenium.webdriver.chrome.options import Options + chrome_options = Options() + chrome_options.add_argument("--headless") + driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) + review_df = pd.DataFrame(columns=["ID", "review-ID", "category", "name", "url", "meta", "star", "review"]) + for idx, item in enumerate(all_items): + market = item["market"] + driver.get(item["url"]) + last_height = driver.execute_script("return document.body.scrollHeight") + try: + wait = WebDriverWait(driver, 10) + wait.until(EC.presence_of_element_located((By.CLASS_NAME, "_11xjFby3Le"))) + except Exception as e: + print("๋ฆฌ๋ทฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", e) + try: + review_button = driver.find_element(By.XPATH, "//a[contains(text(), '๋ฆฌ๋ทฐ')]") + review_button.click() + except Exception as e: + print("๋ฆฌ๋ทฐ ํƒญ ํด๋ฆญ ์‹คํŒจ:", e) + continue + time.sleep(1) + meta_dict = {} + soup = BeautifulSoup(driver.page_source, "html.parser") + try: + meta_star = float(soup.find("strong", class_="_2pgHN-ntx6").get_text()[2:]) + except Exception: + meta_star = None + meta_keys = [key.get_text() for key in soup.find_all("em", class_="_1ehAE1FZXP")] + for key in meta_keys: + try: + button = driver.find_element(By.XPATH, "//button[contains(@class, '_3pfVLZDLde') and @data-shp-area-id='evalnext']") + button.click() + time.sleep(1) + soup = BeautifulSoup(driver.page_source, "html.parser") + detail_keys = [key.get_text() for key in soup.find_all("em", class_="_2QT-bjUbDv")] + detail_values = [int(value.get_text()[:-1]) for value in soup.find_all("span", class_="_1CGcLXygdq")] + detail_dict = {} + for d_k, d_v in zip(detail_keys, detail_values): + detail_dict[d_k] = d_v + meta_dict[key] = detail_dict + except Exception as e: + continue + review_meta_df = pd.DataFrame({ + "ID": f"{market}-{str(idx+1)}", + "review-ID": f"{market}-{str(idx+1)}-0", + "category": item["category"], + "name": item["name"], + "url": item["url"], + "meta": [str(meta_dict)], + "star": meta_star, + }) + try: + latest_button = driver.find_element(By.XPATH, "//a[text()='์ตœ์‹ ์ˆœ']") + latest_button.click() + time.sleep(1) + except Exception as e: + print("์ตœ์‹ ์ˆœ ๋ฒ„ํŠผ ํด๋ฆญ ์‹คํŒจ:", e) + soup = BeautifulSoup(driver.page_source, "html.parser") + try: + review_num = int(soup.find("span", class_="_9Fgp3X8HT7").get_text().replace(",", "")) + except Exception: + review_num = 0 + stars = [] + review_texts = [] + for i in range(2): + try: + scrollTo = driver.find_element(By.CLASS_NAME, "_1McWUwk15j") + driver.execute_script("arguments[0].scrollIntoView();", scrollTo) + except Exception as e: + pass + soup = BeautifulSoup(driver.page_source, "html.parser") + review_divs = soup.find_all("div", class_="_1McWUwk15j") + for review in review_divs: + try: + star = review.find("em", class_="_15NU42F3kT").get_text() + stars.append(star) + except Exception: + stars.append(None) + try: + text_div = review.find("div", class_="_1kMfD5ErZ6").find_all("span") + review_texts.append(text_div[-1].get_text()) + except Exception: + review_texts.append("") + try: + next_page = driver.find_element(By.XPATH, f"//a[contains(@class, 'UWN4IvaQza') and @data-shp-contents-id='{str(i+2)}']") + next_page.click() + time.sleep(2) + except Exception as e: + break + review_text_df = pd.DataFrame(columns=["ID", "review-ID", "star", "review"]) + for i, (star, review) in enumerate(zip(stars, review_texts)): + tmp = pd.DataFrame({ + "ID": f"{market}-{str(idx+1)}", + "review-ID": f"{market}-{str(idx+1)}-{str(i+1)}", + "star": [star], + "review": [review] + }) + review_text_df = pd.concat([review_text_df, tmp], ignore_index=True) + reviews = pd.concat([review_meta_df, review_text_df], ignore_index=True) + review_df = pd.concat([review_df, reviews], ignore_index=True) + driver.quit() + return review_df + +def run_review_crawling(config): + print("\n[์ƒํ’ˆ ์ •๋ณด ๋ฐ ๋ฆฌ๋ทฐ ํฌ๋กค๋ง ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘]\n") + # config์—์„œ ํฌ๋กค๋งํ•  ์ƒํ’ˆ ์ˆ˜ ๋“ฑ ์˜ต์…˜์„ ์ฝ์„ ์ˆ˜ ์žˆ์Œ + CRAWL_LIMIT = 5 + OUTPUT_FILE = os.path.join(config["paths"]["data_dir"], "product_reviews.csv") + mall_category_url = "https://shopping.naver.com/best100v2/main.nhn?catId=50000004" + print("์ƒํ’ˆ URL ์ •๋ณด ์ˆ˜์ง‘ ์ค‘...") + product_urls = get_product_urls(mall_category_url, market="emart", category="์•„์ด๊ฐ„์‹", limit=CRAWL_LIMIT) + print("์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด ์ˆ˜์ง‘ ์ค‘...") + product_details = get_product_details(product_urls, limit=CRAWL_LIMIT) + print("์ƒํ’ˆ ์ƒ์„ธ ์ •๋ณด๋ฅผ CSV๋กœ ์ €์žฅ ์ค‘...") + details_to_csv(product_details) + print("์ƒํ’ˆ ๋ฆฌ๋ทฐ ์ˆ˜์ง‘ ์ค‘...") + review_df = get_product_reviews(product_details[:CRAWL_LIMIT]) + review_df.to_csv(OUTPUT_FILE, index=False) + print("๋ฆฌ๋ทฐ ์ •๋ณด CSV ์ €์žฅ ์™„๋ฃŒ:", OUTPUT_FILE) + print("๋ชจ๋“  ํฌ๋กค๋ง ์ž‘์—… ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + +if __name__ == "__main__": + run_review_crawling({ + "paths": { + "data_dir": "./data" + } + }) diff --git a/models/review/src/sft_pipeline/review_preprocessing.py b/models/review/src/sft_pipeline/review_preprocessing.py new file mode 100644 index 0000000..95dd5d1 --- /dev/null +++ b/models/review/src/sft_pipeline/review_preprocessing.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ] +- ์›๋ณธ ๋ฆฌ๋ทฐ CSV ํŒŒ์ผ์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ „์ฒ˜๋ฆฌ (ํŠน์ˆ˜๋ฌธ์ž ์ œ๊ฑฐ, ๊ฐœํ–‰ ๊ต์ฒด, ์˜์–ด/์ˆซ์ž ํ•„ํ„ฐ, ๊ณต๋ฐฑ ์ •๊ทœํ™”, ๋ฐ˜๋ณต ์ œ๊ฑฐ, ์งง์€ ํ…์ŠคํŠธ ๋ฐฐ์ œ) +- T5 ๋งž์ถค๋ฒ• ๊ต์ • ๋ชจ๋ธ๋กœ ์˜คํƒ€ ๊ต์ • ์ˆ˜ํ–‰ +""" + +import re +import os, sys +import torch +import pandas as pd +from glob import glob +from tqdm import tqdm +from konlpy.tag import Hannanum +from transformers import T5ForConditionalGeneration, T5Tokenizer +from utils.utils import load_and_preprocess_reviews + +hannanum = Hannanum() + +def remove_special_chars(text): + return re.sub(r'[^a-zA-Z0-9๊ฐ€-ํžฃ\s]', '', text) if isinstance(text, str) else "" + +def replace_newlines(text): + return re.sub(r'[\r\n]+', ' ', text).strip() if isinstance(text, str) else "" + +def filter_text_by_english_ratio(text, ratio=0.3): + if not isinstance(text, str) or not text.strip(): + return "" + total = len(text) + eng_count = len(re.findall(r"[a-zA-Z]", text)) + return text if (eng_count / total if total > 0 else 0) <= ratio else "" + +def filter_text_by_number_ratio(text, ratio=0.3): + if not isinstance(text, str) or not text.strip(): + return "" + total = len(text) + num_count = len(re.findall(r"[0-9]", text)) + return text if (num_count / total if total > 0 else 0) <= ratio else "" + +def normalize_whitespace(text): + return re.sub(r'\s+', ' ', text).strip() if isinstance(text, str) else "" + +def remove_repetition(text): + def is_valid_word(word): + pos_tags = hannanum.pos(word) + for token, pos in pos_tags: + if token == word: + return True + return False + def compress_token(token): + if is_valid_word(token): + return token + n = len(token) + for L in range(1, n // 2 + 1): + segment = token[:L] + if segment * (n // L) == token: + return segment + return token + def compress_token_list(tokens): + n = len(tokens) + for k in range(1, n // 2 + 1): + block = tokens[:k] + if block * (n // k) == tokens: + return block + return tokens + if not text or not isinstance(text, str): + return "" + tokens = text.split() + tokens = [compress_token(token) for token in tokens] + tokens = compress_token_list(tokens) + return " ".join(tokens).strip() + +def remove_short_text(text, n=5): + return text if len(text) > n else '' + +MODEL_NAME = "j5ng/et5-typos-corrector" +model = T5ForConditionalGeneration.from_pretrained(MODEL_NAME) +tokenizer = T5Tokenizer.from_pretrained(MODEL_NAME) +device = "cuda:0" if torch.cuda.is_available() else "cpu" +model = model.to(device) + +def batch_correct_typos(df, target_col, batch_size=100): + if target_col not in df.columns: + raise ValueError("๋Œ€์ƒ ์ปฌ๋Ÿผ์ด ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์— ์—†์Šต๋‹ˆ๋‹ค.") + df = df.copy() + df["processed"] = None + for i in tqdm(range(0, len(df), batch_size), desc="๋ฐฐ์น˜ ์ฒ˜๋ฆฌ"): + batch_texts = df[target_col].iloc[i : i + batch_size].tolist() + input_texts = ["๋งž์ถค๋ฒ•์„ ๊ณ ์ณ์ฃผ์„ธ์š”: " + text for text in batch_texts] + encodings = tokenizer(input_texts, return_tensors="pt", padding=True, truncation=True, max_length=128) + input_ids = encodings.input_ids.to(device) + attention_mask = encodings.attention_mask.to(device) + outputs = model.generate( + input_ids=input_ids, + attention_mask=attention_mask, + max_length=128, + num_beams=5, + early_stopping=True + ) + output_texts = tokenizer.batch_decode(outputs, skip_special_tokens=True) + num_rows = min(len(df) - i, len(output_texts)) + col_idx = df.columns.get_loc("processed") + df.iloc[i : i + num_rows, col_idx] = output_texts[:num_rows] + return df + +def run_review_preprocessing(config): + print("\n[๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ์‹œ์ž‘]\n") + input_dir = os.path.join(config["paths"]["crawled_reviews_dir"]) + output_dir = os.path.join(config["paths"]["preprocessed_dir"]) + os.makedirs(output_dir, exist_ok=True) + csv_files = glob(os.path.join(input_dir, "*.csv")) + if not csv_files: + print("์ฒ˜๋ฆฌํ•  CSV ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.") + return + for src_file in csv_files: + base_name = os.path.basename(src_file).replace("crawled_", "processed_", 1) + dest_file = os.path.join(output_dir, base_name) + meta_base_name = os.path.basename(src_file).replace("crawled_", "meta_", 1) + meta_dest_file = os.path.join(output_dir, meta_base_name) + try: + meta_df, df = load_and_preprocess_reviews(src_file) + meta_df.to_csv(meta_dest_file, index=False) + except Exception as e: + print(f"ํŒŒ์ผ ๋กœ๋“œ ์‹คํŒจ ({src_file}): {e}") + continue + tqdm.pandas() + df["step_special"] = df["review"].progress_apply(remove_special_chars) + df["step_newline"] = df["step_special"].apply(replace_newlines) + df["step_eng_filter"] = df["step_newline"].apply(filter_text_by_english_ratio) + df["step_num_filter"] = df["step_eng_filter"].apply(filter_text_by_number_ratio) + df["step_whitespace"] = df["step_num_filter"].apply(normalize_whitespace) + df["step_repetition"] = df["step_whitespace"].progress_apply(remove_repetition) + df["step_length"] = df["step_repetition"].apply(remove_short_text) + df = df[(df["step_length"] != "") & df["step_length"].notna()] + df = batch_correct_typos(df, "step_length", batch_size=100) + drop_cols = ["step_special", "step_newline", "step_eng_filter", + "step_num_filter", "step_whitespace", "step_repetition", "step_length"] + df.drop(columns=drop_cols, inplace=True) + df.to_csv(dest_file, index=False) + print(f"\n[์ „์ฒ˜๋ฆฌ ๋ฐ์ดํ„ฐ ์ €์žฅ] {dest_file}\n") + print("\n[๋ฆฌ๋ทฐ ์ „์ฒ˜๋ฆฌ ์™„๋ฃŒ]\n") + +if __name__ == "__main__": + run_review_preprocessing({ + "paths": { + "data_dir": "./data", + "crawled_reviews": "./data/crawled_reviews", + "preprocessed_dir": "./data/preprocessed" + } + }) diff --git a/models/review/src/sft_pipeline/sft.py b/models/review/src/sft_pipeline/sft.py new file mode 100644 index 0000000..da54c66 --- /dev/null +++ b/models/review/src/sft_pipeline/sft.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def run_sft(config): + print("๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + print("qwen_deepseek_14,32b_finetuning.py ํŒŒ์ผ๋กœ SFT๋ฅผ ์ง„ํ–‰ํ•˜์„ธ์š”.\n") + +if __name__ == "__main__": + run_sft({"paths": {}}) diff --git a/models/review/src/sft_pipeline/train_data_annotating.py b/models/review/src/sft_pipeline/train_data_annotating.py new file mode 100644 index 0000000..cc0b512 --- /dev/null +++ b/models/review/src/sft_pipeline/train_data_annotating.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[ํ•™์Šต๋ฐ์ดํ„ฐ ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ] +- ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํŒŒ์ผ์—์„œ ์•„์ง ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ๋ฆฌ๋ทฐ์— ๋Œ€ํ•ด GPT API ํ˜ธ์ถœ +- Few-shot ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ๋ฉ”์‹œ์ง€ ๊ตฌ์„ฑํ•˜์—ฌ ์‘๋‹ต ์ƒ์„ฑ +- ์‘๋‹ต์—์„œ ํƒœ๊ทธ์˜ Reasoning ๋ฐ ```json``` ๋ธ”๋ก์˜ Answer ์ถ”์ถœ +- ๊ฒฐ๊ณผ๋ฅผ CSV ํŒŒ์ผ๋กœ ์ €์žฅ +""" + +import os +import re +import json +import pandas as pd +from tqdm import tqdm +from openai import OpenAI +from dotenv import load_dotenv +# prompt ๋ชจ๋“ˆ์—์„œ ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. +from prompt.prompt_loader import load_prompt, load_fewshot + +def run_train_data_annotating(config): + # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ + load_dotenv(os.path.expanduser("~/.env")) + OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") + if not OPENAI_API_KEY: + raise ValueError("OPENAI_API_KEY๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. .env ํŒŒ์ผ์„ ํ™•์ธํ•˜์„ธ์š”.") + os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY + + # ํŒŒ์ผ ๊ฒฝ๋กœ๋Š” config๋ฅผ ํ†ตํ•ด ์ฝ์Œ + aste_dir = config["paths"]["aste_dir"] + train_dir = config["paths"]["train_dir"] + input_file = os.path.join(aste_dir, "aste_sampled.csv") + output_temp_file = os.path.join(train_dir, "train_data_TEMP.csv") + output_final_file = os.path.join(train_dir, "train_data.csv") + BATCH_SIZE = 10 + MODEL = config["train_data_annotating"]["annotation_model"] + + PROMPT = load_prompt(prompt_filename="annotation_prompt.txt", + prompt_dir="./prompt/review_annotation/") + FEW_SHOT = load_fewshot(fewshot_filename="annotation_fewshot.json", + prompt_dir="./prompt/review_annotation/") + + client = OpenAI() + + print("\n[ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ์‹œ์ž‘]\n") + + df = pd.read_csv(input_file) + if os.path.exists(output_temp_file): + existing = pd.read_csv(output_temp_file) + else: + existing = pd.DataFrame() + processed_ids = set(existing["review-ID"]) if not existing.empty else set() + remaining = df[~df["review-ID"].isin(processed_ids)].copy() + print(f"๋‚จ์€ ๋ฐ์ดํ„ฐ ์ˆ˜: {len(remaining)}\n") + + results = [] + for i in tqdm(range(0, len(remaining), BATCH_SIZE), desc="GPT ์ฒ˜๋ฆฌ"): + batch = remaining.iloc[i : i + BATCH_SIZE] + for _, row in batch.iterrows(): + messages = [{"role": "system", "content": PROMPT}] + for example in FEW_SHOT: + messages.append({"role": "user", "content": example["query"]}) + messages.append({"role": "assistant", "content": example["answer"]}) + messages.append({"role": "user", "content": row["processed"]}) + + completion = client.chat.completions.create( + model=MODEL, + messages=messages, + ) + response = completion.choices[0].message.content + entry = row.to_dict() + entry["GPT_Response"] = response + results.append(entry) + + df_batch = pd.DataFrame(results) + if os.path.exists(output_temp_file): + df_batch.to_csv(output_temp_file, mode="a", header=False, index=False) + else: + df_batch.to_csv(output_temp_file, mode="w", header=True, index=False) + print(f"์ฒ˜๋ฆฌ ์™„๋ฃŒ: {i + len(batch)} / {len(remaining)} ๊ฑด") + results = [] + print("\n๋ชจ๋“  ๋ฐ์ดํ„ฐ GPT ์ฒ˜๋ฆฌ ์™„๋ฃŒ.\n") + + df_temp = pd.read_csv(output_temp_file) + results = [] + for _, row in df_temp.iterrows(): + resp = row.get("GPT_Response", "") + reasoning = "" + answer = "" + try: + match_think = re.search(r"(.*?)", resp, re.DOTALL) + if match_think: + reasoning = match_think.group(1).strip() + except Exception: + reasoning = "" + try: + match_json = re.search(r"```json\n(.*?)\n```", resp, re.DOTALL) + if match_json: + answer = match_json.group(1).strip() + except Exception: + answer = "" + entry = row.copy() + entry["GPT_Reasoning"] = reasoning + entry["GPT_Answer"] = answer + results.append(entry) + df_final = pd.DataFrame(results) + df_final.to_csv(output_final_file, index=False) + + if os.path.exists(output_temp_file) and (df_temp.shape[0] == df.shape[0]): + os.remove(output_temp_file) + + + print("[์ตœ์ข… ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐ์ดํ„ฐ ์ €์žฅ]", output_final_file) + + print("\n[ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ์™„๋ฃŒ]\n") + +if __name__ == "__main__": + run_train_data_annotating({ + "paths": { + "data_dir": "./data", + "prompt_dir": "./prompt" + }, + "pipeline": {"sft": {"review_annotation": True}} + }) diff --git a/models/review/src/sft_pipeline/train_data_sampling.py b/models/review/src/sft_pipeline/train_data_sampling.py new file mode 100644 index 0000000..01bd54a --- /dev/null +++ b/models/review/src/sft_pipeline/train_data_sampling.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ๋ง ํŒŒ์ดํ”„๋ผ์ธ] +1. ์ „์ฒ˜๋ฆฌ๋œ ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ์—์„œ ๊ณจ๋“  ๋ฐ ์ˆ˜๋™ ๋ ˆ์ด๋ธ” ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์™ธ +2. Sentence-BERT ์ž„๋ฒ ๋”ฉ์„ ์ด์šฉํ•˜์—ฌ ๋ฆฌ๋ทฐ ๋ฒกํ„ฐ ์ƒ์„ฑ +3. K-Means ํด๋Ÿฌ์Šคํ„ฐ๋ง์œผ๋กœ 900๊ฐœ ํด๋Ÿฌ์Šคํ„ฐ ์ƒ์„ฑ ํ›„ ๊ฐ ํด๋Ÿฌ์Šคํ„ฐ ์ค‘์‹ฌ ์ƒ˜ํ”Œ ์„ ํƒ +4. ๋Œ€ํ‘œ ์ƒ˜ํ”Œ CSV ํŒŒ์ผ๋กœ ์ €์žฅ +""" + +import os +import sys +import json +import numpy as np +import pandas as pd +from collections import Counter +from sklearn.cluster import KMeans +from tqdm import tqdm +from glob import glob + +# utils ๋ชจ๋“ˆ์—์„œ ์ž„๋ฒ ๋”ฉ ํ•จ์ˆ˜๋ฅผ import +from utils.utils import sentenceBERT_embeddings + +def filter_data(config): + preprocessed_dir = os.path.join(config["paths"]["preprocessed_dir"]) + csv_files = glob(os.path.join(preprocessed_dir, "*.csv")) + csv_files = [f for f in glob(os.path.join(preprocessed_dir, "*.csv")) + if not (os.path.basename(f).startswith("meta_") + or os.path.basename(f).endswith("_all.csv"))] + + df_list = [pd.read_csv(file) for file in csv_files] + merged_df = pd.concat(df_list, ignore_index=True) + merged_output = os.path.join(preprocessed_dir, "processed_reviews_all.csv") + merged_df.to_csv(merged_output, index=False) + print(f"[์ „์ฒด ์ „์ฒ˜๋ฆฌ ๋ฐ์ดํ„ฐ ์ €์žฅ] {merged_output}\n") + + raw_df = pd.read_csv(merged_output) + golden_file = os.path.join(config["paths"]["eval_dir"], "aste_annotation_100_golden_label.csv") + golden_df = pd.read_csv(golden_file) + df_filtered = raw_df[~raw_df['review-ID'].isin(golden_df['review-ID'])] + output_filtered = os.path.join(config["paths"]["aste_dir"], "processed_except_GL.csv") + df_filtered.to_csv(output_filtered, index=False) + print(f"[๊ณจ๋“  ๋ผ๋ฒจ ์ œ์™ธ ์ „์ฒ˜๋ฆฌ ๋ฐ์ดํ„ฐ ์ €์žฅ] {output_filtered}") + return output_filtered + +def perform_kmeans_clustering(embeddings: np.ndarray, num_clusters=900, random_state=42): + print("K-Means ํด๋Ÿฌ์Šคํ„ฐ๋ง ์ˆ˜ํ–‰ ์ค‘...\n") + kmeans = KMeans(n_clusters=num_clusters, random_state=random_state, n_init=10) + labels = kmeans.fit_predict(embeddings) + return kmeans, labels, num_clusters + +def select_representative_samples(kmeans, cluster_labels: np.ndarray, num_clusters, embeddings: np.ndarray) -> list: + selected_idx = [] + for cid in tqdm(range(num_clusters), desc="๋Œ€ํ‘œ ์ƒ˜ํ”Œ ์„ ํƒ"): + indices = np.where(cluster_labels == cid)[0] + center = kmeans.cluster_centers_[cid] + closest = indices[np.argmin(np.linalg.norm(embeddings[indices] - center, axis=1))] + selected_idx.append(closest) + return selected_idx + +def run_train_data_sampling(config): + print("\n[ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ๋ง ์‹œ์ž‘]\n") + filtered_file = filter_data(config) + embedding_path = os.path.join(config["paths"]["embedding_dir"], "train_sampling.npy") + raw_data = pd.read_csv(filtered_file) + embedding_matrix = sentenceBERT_embeddings(embedding_path, raw_data, column="processed") + kmeans, labels, num_clusters = perform_kmeans_clustering(embedding_matrix, num_clusters=config["train_data_annotating"]["num_train_data"]) + selected_indices = select_representative_samples(kmeans, labels, num_clusters, embedding_matrix) + sampled_df = raw_data.iloc[selected_indices].reset_index(drop=True) + output_file = os.path.join(config["paths"]["aste_dir"], "aste_sampled.csv") + sampled_df.to_csv(output_file, index=False) + print("\n[ํ•™์Šต ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ๋ง ์™„๋ฃŒ]", output_file) + +if __name__ == "__main__": + run_train_data_sampling({ + "paths": { + "data_dir": "./data", + "embedding_dir": "./data/embedding_matrics" + } + }) diff --git a/models/review/utils/__init__.py b/models/review/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/review/utils/evaluate.py b/models/review/utils/evaluate.py new file mode 100644 index 0000000..1a2a0b0 --- /dev/null +++ b/models/review/utils/evaluate.py @@ -0,0 +1,409 @@ +import json +import numpy as np +import pandas as pd +import seaborn as sns +from tqdm import tqdm +from ast import literal_eval +from bert_score import score +import matplotlib.pyplot as plt +import matplotlib.font_manager as fm +from scipy.optimize import linear_sum_assignment +from sklearn.metrics import confusion_matrix, classification_report + + +""" +์‚ฌ์šฉ ์˜ˆ์‹œ: +sys.path.append(os.path.abspath('../src')) +from evaluate import evaluate_aste + +evaluate_aste( + df, + golden_label_col="aste_golden_label", + model_prediction_col="aste_hcx", + # eval_threshold=0.85 +) +""" + + + +# ํ•œ๊ธ€ ํฐํŠธ ์„ค์ • (Ubuntu์—์„œ๋Š” 'NanumGothic' ์‚ฌ์šฉ) +plt.rc('font', family='NanumGothic') +# ๋งˆ์ด๋„ˆ์Šค ๊ธฐํ˜ธ ๊นจ์ง ๋ฐฉ์ง€ +plt.rcParams['axes.unicode_minus'] = False + +# def extract_triplets(json_str): +# """ +# JSON ํฌ๋งท ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•˜์—ฌ triplet ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜. +# ๊ฐ triplet์€ {"์†์„ฑ": ..., "ํ‰๊ฐ€": ..., "๊ฐ์ •": ...} ํ˜•์‹์ž„. +# """ +# try: +# triplets = json.loads(json_str) +# return triplets +# except Exception as e: +# print("JSON ํŒŒ์‹ฑ ์—๋Ÿฌ:", e) +# print(json_str) +# return [] + + +def extract_triplets(json_str): + """ + JSON ํฌ๋งท ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•˜์—ฌ triplet ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜. + ๊ฐ triplet์€ {"์†์„ฑ": ..., "ํ‰๊ฐ€": ..., "๊ฐ์ •": ...} ํ˜•์‹์ž„. + ๋งŒ์•ฝ "์†์„ฑ", "ํ‰๊ฐ€", "๊ฐ์ •" ํ‚ค๊ฐ€ ์—†์œผ๋ฉด ๊ฐ๊ฐ ๋นˆ ๋ฌธ์ž์—ด("")์„ ๋„ฃ์Œ. + """ + try: + triplets = literal_eval(json_str) + + # ๊ฐ triplet์— ๋Œ€ํ•ด ํ‚ค๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๋ฌธ์ž์—ด("")์„ ๋„ฃ์Œ + for triplet in triplets: + triplet["์†์„ฑ"] = triplet.get("์†์„ฑ", "") + triplet["ํ‰๊ฐ€"] = triplet.get("ํ‰๊ฐ€", "") + triplet["๊ฐ์ •"] = triplet.get("๊ฐ์ •", "") + + return triplets + except Exception as e: + print("JSON ํŒŒ์‹ฑ ์—๋Ÿฌ:", e) + print(json_str) + return [] + + +def bertscore_similarity(text1, text2): + """ + BERTScore๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ๋ฌธ์žฅ์˜ ์œ ์‚ฌ๋„๋ฅผ ์ธก์ •ํ•จ. + F1-score๋ฅผ ๋ฐ˜ํ™˜ (0~1). + """ + P, R, F1 = score([text1], [text2], lang="ko", verbose=False, device="cuda") + return F1.item() + + +def match_triplets(gl_triplets, hcx_triplets, eval_threshold=0.85): + """ + GL์™€ HCX์˜ triplet ๋ฆฌ์ŠคํŠธ ๊ฐ„์— 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์˜ BERTScore ์œ ์‚ฌ๋„๋ฅผ ๊ธฐ์ค€์œผ๋กœ + 1:1 ๋งค์นญ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. Hungarian Algorithm์„ ํ™œ์šฉํ•˜๋ฉฐ, ์œ ์‚ฌ๋„๊ฐ€ eval_threshold ์ด์ƒ์ธ ๊ฒฝ์šฐ๋งŒ ํ›„๋ณด๋กœ ์„ ์ •ํ•œ๋‹ค. + + ๋ฐ˜ํ™˜: [(gl_index, hcx_index, similarity), ...] (similarity >= eval_threshold) + """ + if len(gl_triplets) == 0 or len(hcx_triplets) == 0: + return [] # ๋งค์นญ ๋ถˆ๊ฐ€ + + num_gl = len(gl_triplets) + num_hcx = len(hcx_triplets) + cost_matrix = np.zeros((num_gl, num_hcx)) + sim_matrix = np.zeros((num_gl, num_hcx)) + + # ๊ฐ pair์— ๋Œ€ํ•ด 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์˜ ์œ ์‚ฌ๋„๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ cost matrix ๊ตฌ์„ฑ + for i, gl in enumerate(gl_triplets): + for j, hcx in enumerate(hcx_triplets): + sim = bertscore_similarity(gl["ํ‰๊ฐ€"], hcx["ํ‰๊ฐ€"]) + sim_matrix[i, j] = sim + cost_matrix[i, j] = 1 - sim # cost: ์œ ์‚ฌ๋„๊ฐ€ ๋†’์œผ๋ฉด ๋‚ฎ์€ cost + + # Hungarian Algorithm ์ ์šฉ + row_ind, col_ind = linear_sum_assignment(cost_matrix) + candidate_matches = [] + for i, j in zip(row_ind, col_ind): + sim = sim_matrix[i, j] + if sim >= eval_threshold: + candidate_matches.append((i, j, sim)) + return candidate_matches + + +def evaluate_instance(gl_triplets, hcx_triplets, eval_threshold=0.85): + """ + ํ•œ ์ธ์Šคํ„ด์Šค(ํ•˜๋‚˜์˜ ์›๋ฌธ)์— ๋Œ€ํ•ด GL์™€ HCX triplet ์„ธํŠธ๋ฅผ ํ‰๊ฐ€ํ•œ๋‹ค. + + 1. Hungarian Algorithm์„ ํ†ตํ•ด 'ํ‰๊ฐ€' ํ•ญ๋ชฉ ๊ธฐ๋ฐ˜ 1:1 ๋งค์นญ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. + 2. ๋งค์นญ๋œ ๊ฐ triplet ํ›„๋ณด์— ๋Œ€ํ•ด: + - 'ํ‰๊ฐ€': ์œ ์‚ฌ๋„๊ฐ€ eval_threshold ์ด์ƒ์ด๋ฏ€๋กœ TP๋กœ ๊ฐ„์ฃผ. + - '์†์„ฑ'๊ณผ '๊ฐ์ •': GL์™€ HCX ๊ฐ’์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋ฉด TP, ๋ถˆ์ผ์น˜ํ•˜๋ฉด ์˜ค๋ฅ˜๋กœ ๊ฐ„์ฃผํ•˜์—ฌ + ๋ผ๋ฒจ ์ธก๋ฉด์—์„œ FN, ์˜ˆ์ธก ์ธก๋ฉด์—์„œ FP๋กœ ๊ธฐ๋ก. + 3. ๋งค์นญ๋˜์ง€ ์•Š์€ triplet์— ๋Œ€ํ•ด์„œ๋Š”: + - ๋ผ๋ฒจ์—๋งŒ ์žˆ์œผ๋ฉด FN (์„ธ ํ•ญ๋ชฉ ๋ชจ๋‘) + - ์˜ˆ์ธก์—๋งŒ ์žˆ์œผ๋ฉด FP (์„ธ ํ•ญ๋ชฉ ๋ชจ๋‘) + + ๋ฐ˜ํ™˜: {'์†์„ฑ': {"TP": ..., "FN": ..., "FP": ...}, + 'ํ‰๊ฐ€': {"TP": ..., "FN": ..., "FP": ...}, + '๊ฐ์ •': {"TP": ..., "FN": ..., "FP": ...}} + """ + # ์ดˆ๊ธฐํ™” + counts = { + "์†์„ฑ": {"TP": 0, "FN": 0, "FP": 0}, + "ํ‰๊ฐ€": {"TP": 0, "FN": 0, "FP": 0}, + "๊ฐ์ •": {"TP": 0, "FN": 0, "FP": 0} + } + + # 1:1 ๋งค์นญ (ํ‰๊ฐ€ ํ•ญ๋ชฉ ๊ธฐ์ค€) + candidate_matches = match_triplets(gl_triplets, hcx_triplets, eval_threshold) + matched_gl_indices = set() + matched_hcx_indices = set() + + # ๋งค์นญ๋œ ํ›„๋ณด๋“ค์— ๋Œ€ํ•ด ์„ธ๋ถ€ ํ‰๊ฐ€ + for i, j, sim in candidate_matches: + matched_gl_indices.add(i) + matched_hcx_indices.add(j) + + # 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์€ ์œ ์‚ฌ๋„ eval_threshold ์ด์ƒ์ด๋ฏ€๋กœ TP๋กœ ๊ธฐ๋ก + counts["ํ‰๊ฐ€"]["TP"] += 1 + + # '์†์„ฑ' ํ‰๊ฐ€: ์ผ์น˜ํ•˜๋ฉด TP, ๋ถˆ์ผ์น˜๋ฉด ์˜ค๋ฅ˜๋กœ FN(๋ผ๋ฒจ) ๋ฐ FP(์˜ˆ์ธก) ์ฒ˜๋ฆฌ + if gl_triplets[i]["์†์„ฑ"] == hcx_triplets[j]["์†์„ฑ"]: + counts["์†์„ฑ"]["TP"] += 1 + else: + counts["์†์„ฑ"]["FN"] += 1 + counts["์†์„ฑ"]["FP"] += 1 + + # '๊ฐ์ •' ํ‰๊ฐ€: ์ผ์น˜ํ•˜๋ฉด TP, ๋ถˆ์ผ์น˜๋ฉด ์˜ค๋ฅ˜๋กœ FN ๋ฐ FP ์ฒ˜๋ฆฌ + if gl_triplets[i]["๊ฐ์ •"] == hcx_triplets[j]["๊ฐ์ •"]: + counts["๊ฐ์ •"]["TP"] += 1 + else: + counts["๊ฐ์ •"]["FN"] += 1 + counts["๊ฐ์ •"]["FP"] += 1 + + # ๋งค์นญ๋˜์ง€ ์•Š์€ triplet ์ฒ˜๋ฆฌ + # ๋ผ๋ฒจ์—๋งŒ ์žˆ๋Š” triplet: FN (์„ธ ํ•ญ๋ชฉ ๋ชจ๋‘) + for idx in range(len(gl_triplets)): + if idx not in matched_gl_indices: + counts["์†์„ฑ"]["FN"] += 1 + counts["ํ‰๊ฐ€"]["FN"] += 1 + counts["๊ฐ์ •"]["FN"] += 1 + # ์˜ˆ์ธก์—๋งŒ ์žˆ๋Š” triplet: FP (์„ธ ํ•ญ๋ชฉ ๋ชจ๋‘) + for idx in range(len(hcx_triplets)): + if idx not in matched_hcx_indices: + counts["์†์„ฑ"]["FP"] += 1 + counts["ํ‰๊ฐ€"]["FP"] += 1 + counts["๊ฐ์ •"]["FP"] += 1 + + return counts + + +def aggregate_evaluation(df, golden_label_col, model_prediction_col, eval_threshold=0.85): + """ + ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„(df)์˜ ๊ฐ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•ด GL์™€ HCX triplet ์„ธํŠธ๋ฅผ ํ‰๊ฐ€ํ•˜๊ณ , + ์ „์ฒด TP, FN, FP๋ฅผ ์ง‘๊ณ„ํ•˜์—ฌ '์†์„ฑ', 'ํ‰๊ฐ€', '๊ฐ์ •' ๊ฐ๊ฐ์— ๋Œ€ํ•ด Precision, Recall, F1์„ ๊ณ„์‚ฐํ•œ๋‹ค. + + ๋™์‹œ์— ์†์„ฑ(Aspect)๊ณผ ๊ฐ์ •(Sentiment)์˜ gold/pred ๋ผ๋ฒจ์„ ์ˆ˜์ง‘ํ•˜๋Š”๋ฐ, + ๋‹จ์ˆœํžˆ 1:1 ๋งค์นญ๋œ ๊ฒฝ์šฐ๋ฟ ์•„๋‹ˆ๋ผ, ๋งค์นญ๋˜์ง€ ์•Š์€ triplet์— ๋Œ€ํ•ด + - GL์—๋งŒ ์กด์žฌํ•˜๋ฉด predicted๋Š” "NO_PRED"๋กœ, + - ์˜ˆ์ธก์—๋งŒ ์กด์žฌํ•˜๋ฉด gold๋Š” "NO_GOLD"๋กœ ๊ธฐ๋กํ•˜์—ฌ ์ „์ฒด ํ‰๊ฐ€์— ๋ฐ˜์˜ํ•œ๋‹ค. + + ๋˜ํ•œ, 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์˜ BERTScore ์œ ์‚ฌ๋„ ๋ฆฌ์ŠคํŠธ๋„ ์ถ•์ ํ•œ๋‹ค. + + ๋ฐ˜ํ™˜: + - metrics: ์†์„ฑ, ํ‰๊ฐ€, ๊ฐ์ •์— ๋Œ€ํ•œ Precision, Recall, F1-score ๋ฐ TP, FN, FP ๊ฐœ์ˆ˜ + - classification_data: [aspects_gold, aspects_pred, sentiments_gold, sentiments_pred] (์ „์ฒด ์‚ฌ๋ก€) + - eval_similarities: ํ‰๊ฐ€(BERTScore) ์œ ์‚ฌ๋„ ๋ฆฌ์ŠคํŠธ (๋งค์นญ๋œ ๊ฒฝ์šฐ๋งŒ) + """ + total_counts = { + "์†์„ฑ": {"TP": 0, "FN": 0, "FP": 0}, + "ํ‰๊ฐ€": {"TP": 0, "FN": 0, "FP": 0}, + "๊ฐ์ •": {"TP": 0, "FN": 0, "FP": 0} + } + + # ์ „์ฒด classification ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ๋ฆฌ์ŠคํŠธ (๋งค์นญ๋œ ๊ฒฝ์šฐ์™€ ๋ฏธ๋งค์นญ ์‚ฌ๋ก€ ํฌํ•จ) + aspects_gold_all = [] + aspects_pred_all = [] + sentiments_gold_all = [] + sentiments_pred_all = [] + eval_similarities = [] + + for idx, row in tqdm(df.iterrows(), total=len(df)): + gl_triplets = extract_triplets(row[golden_label_col]) + hcx_triplets = extract_triplets(row[model_prediction_col]) + + candidate_matches = match_triplets(gl_triplets, hcx_triplets, eval_threshold) + matched_gl_indices = set([i for i, j, sim in candidate_matches]) + matched_hcx_indices = set([j for i, j, sim in candidate_matches]) + + # ๋งค์นญ๋œ ๊ฒฝ์šฐ: ์‹ค์ œ ๋ผ๋ฒจ์„ ๊ธฐ๋ก + for i, j, sim in candidate_matches: + aspects_gold_all.append(gl_triplets[i]["์†์„ฑ"]) + aspects_pred_all.append(hcx_triplets[j]["์†์„ฑ"]) + sentiments_gold_all.append(gl_triplets[i]["๊ฐ์ •"]) + sentiments_pred_all.append(hcx_triplets[j]["๊ฐ์ •"]) + eval_similarities.append(sim) + + # ๋งค์นญ๋˜์ง€ ์•Š์€ GL triplet: ์˜ˆ์ธก์ด ์—†์œผ๋ฏ€๋กœ predicted๋ฅผ "NO_PRED"๋กœ ๊ธฐ๋ก + for idx_gl, gl_triplet in enumerate(gl_triplets): + if idx_gl not in matched_gl_indices: + aspects_gold_all.append(gl_triplet["์†์„ฑ"]) + aspects_pred_all.append("NO_PRED") + sentiments_gold_all.append(gl_triplet["๊ฐ์ •"]) + sentiments_pred_all.append("NO_PRED") + + # ๋งค์นญ๋˜์ง€ ์•Š์€ ์˜ˆ์ธก triplet: GL์— ํ•ด๋‹นํ•˜๋Š” ํ•ญ๋ชฉ์ด ์—†์œผ๋ฏ€๋กœ gold๋ฅผ "NO_GOLD"๋กœ ๊ธฐ๋ก + for idx_hcx, hcx_triplet in enumerate(hcx_triplets): + if idx_hcx not in matched_hcx_indices: + aspects_gold_all.append("NO_GOLD") + aspects_pred_all.append(hcx_triplet["์†์„ฑ"]) + sentiments_gold_all.append("NO_GOLD") + sentiments_pred_all.append(hcx_triplet["๊ฐ์ •"]) + + # ์ธ์Šคํ„ด์Šค๋ณ„ ํ‰๊ฐ€ (์ „์ฒด TP/FN/FP ์ง‘๊ณ„) + counts = evaluate_instance(gl_triplets, hcx_triplets, eval_threshold) + for field in total_counts: + total_counts[field]["TP"] += counts[field]["TP"] + total_counts[field]["FN"] += counts[field]["FN"] + total_counts[field]["FP"] += counts[field]["FP"] + + # ๊ฐ ํ•„๋“œ๋ณ„ Precision, Recall, F1 ๊ณ„์‚ฐ + metrics = {} + for field, vals in total_counts.items(): + TP = vals["TP"] + FN = vals["FN"] + FP = vals["FP"] + precision = TP / (TP + FP) if (TP + FP) > 0 else 0 + recall = TP / (TP + FN) if (TP + FN) > 0 else 0 + f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) > 0 else 0 + metrics[field] = { + "Precision": precision, + "Recall": recall, + "F1": f1, + "TP": TP, + "FN": FN, + "FP": FP + } + + # ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print("์ตœ์ข… ํ‰๊ฐ€ ๊ฒฐ๊ณผ:") + for field, m in metrics.items(): + print(f"{field} -> Precision: {m['Precision']:.4f}, Recall: {m['Recall']:.4f}, F1: {m['F1']:.4f} (TP: {m['TP']}, FN: {m['FN']}, FP: {m['FP']})") + + classification_data = [aspects_gold_all, aspects_pred_all, sentiments_gold_all, sentiments_pred_all] + return metrics, classification_data, eval_similarities + + +def extract_unique_labels(df, golden_label_col, model_prediction_col, field): + """ + ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„(df)์—์„œ ์†์„ฑ(Aspect) ๋ฐ ๊ฐ์ •(Sentiment)์˜ ์œ ๋‹ˆํฌํ•œ ๊ฐ’๋“ค์„ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜ + """ + labels = set() + + for _, row in df.iterrows(): + gl_triplets = extract_triplets(row[golden_label_col]) + hcx_triplets = extract_triplets(row[model_prediction_col]) + for triplet in gl_triplets + hcx_triplets: + labels.add(triplet[field]) + + # "NO_PRED"์™€ "NO_GOLD"๋„ ๊ฒฐ๊ณผ์— ํฌํ•จ + labels.update(["NO_PRED", "NO_GOLD"]) + return sorted(list(labels)) + + +def plot_confusion_matrix(y_true, y_pred, labels, title="Confusion Matrix"): + """ + Confusion Matrix๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ํ•จ์ˆ˜ + """ + cm = confusion_matrix(y_true, y_pred, labels=labels) + df_cm = pd.DataFrame(cm, index=labels, columns=labels) + + plt.figure(figsize=(6, 5)) + sns.heatmap(df_cm, annot=True, fmt="d", cmap="Blues", xticklabels=labels, yticklabels=labels) + plt.xlabel("Predicted Label") + plt.ylabel("True Label") + plt.title(title) + plt.show() + + +def plot_evaluation_similarity(eval_similarities): + """ + 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์˜ BERTScore ์œ ์‚ฌ๋„ ๊ฐ’์„ ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ ์‹œ๊ฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜ + """ + if not eval_similarities: + print("ํ‰๊ฐ€ ์œ ์‚ฌ๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + + avg_similarity = np.mean(eval_similarities) + median_similarity = np.median(eval_similarities) + std_similarity = np.std(eval_similarities) + + plt.figure(figsize=(6, 5)) + sns.histplot(eval_similarities, bins=20, kde=True, color='blue') + plt.axvline(avg_similarity, color='red', linestyle='dashed', linewidth=2, label=f'ํ‰๊ท : {avg_similarity:.4f}') + plt.axvline(median_similarity, color='green', linestyle='dashed', linewidth=2, label=f'์ค‘์•™๊ฐ’: {median_similarity:.4f}') + plt.xlabel("BERTScore Similarity") + plt.ylabel("Frequency") + plt.title("Evaluation BERTScore Similarity Distribution") + plt.legend() + plt.show() + + +def compute_confusion_and_report(df, golden_label_col, model_prediction_col, classification_data): + """ + ์ถ•์ ๋œ gold์™€ predicted ๋ผ๋ฒจ์„ ์ด์šฉํ•˜์—ฌ, ์†์„ฑ๊ณผ ๊ฐ์ •์— ๋Œ€ํ•œ Confusion Matrix์™€ + Classification Report๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. + """ + aspects_gold, aspects_pred, sentiments_gold, sentiments_pred = classification_data + + print("=== ์†์„ฑ (Aspect) Confusion Matrix ===") + aspect_labels = extract_unique_labels(df, golden_label_col, model_prediction_col, "์†์„ฑ") + plot_confusion_matrix(aspects_gold, aspects_pred, labels=aspect_labels, title="Aspect Confusion Matrix") + + print("\n=== ์†์„ฑ (Aspect) Classification Report ===") + print(classification_report(aspects_gold, aspects_pred)) + + print("=== ๊ฐ์ • (Sentiment) Confusion Matrix ===") + sentiment_labels = extract_unique_labels(df, golden_label_col, model_prediction_col, "๊ฐ์ •") + plot_confusion_matrix(sentiments_gold, sentiments_pred, labels=sentiment_labels, title="Sentiment Confusion Matrix") + + print("\n=== ๊ฐ์ • (Sentiment) Classification Report ===") + print(classification_report(sentiments_gold, sentiments_pred)) + + +def compute_eval_statistics(eval_similarities): + """ + 'ํ‰๊ฐ€' ํ•ญ๋ชฉ์˜ BERTScore ์œ ์‚ฌ๋„ ๊ฐ’์— ๋Œ€ํ•ด ํ‰๊ท , ์ค‘์•™๊ฐ’, ๋ถ„ํฌ ๋“ฑ ํ†ต๊ณ„๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. + """ + if not eval_similarities: + print("ํ‰๊ฐ€ ์œ ์‚ฌ๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return None + avg_similarity = np.mean(eval_similarities) + median_similarity = np.median(eval_similarities) + std_similarity = np.std(eval_similarities) + + plot_evaluation_similarity(eval_similarities) + + print("=== ํ‰๊ฐ€ (Evaluation) ์œ ์‚ฌ๋„ ํ†ต๊ณ„ ===") + print(f"ํ‰๊ท  ์œ ์‚ฌ๋„: {avg_similarity:.4f}") + print(f"์ค‘์•™๊ฐ’ ์œ ์‚ฌ๋„: {median_similarity:.4f}") + print(f"ํ‘œ์ค€ํŽธ์ฐจ: {std_similarity:.4f}") + + return avg_similarity, median_similarity, std_similarity + + +def evaluate_aste(df, golden_label_col, model_prediction_col, eval_threshold=0.85): + """ + ์ „์ฒด ํ‰๊ฐ€ ๊ณผ์ •์„ ํ•œ ๋ฒˆ์— ์‹คํ–‰ํ•˜๋Š” Wrapper ํ•จ์ˆ˜. + + 1. aggregate_evaluation() ์‹คํ–‰ํ•˜์—ฌ ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ, Confusion Matrix์šฉ ๋ฐ์ดํ„ฐ, ์œ ์‚ฌ๋„ ๋ฆฌ์ŠคํŠธ ๊ณ„์‚ฐ + 2. compute_confusion_and_report() ์‹คํ–‰ํ•˜์—ฌ Confusion Matrix ๋ฐ Classification Report ์ถœ๋ ฅ + 3. compute_eval_statistics() ์‹คํ–‰ํ•˜์—ฌ BERTScore ์œ ์‚ฌ๋„ ํ†ต๊ณ„ ์ถœ๋ ฅ + + Args: + df (pd.DataFrame): ํ‰๊ฐ€ํ•  ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ + golden_label_col (str): ๊ณจ๋“  ๋ผ๋ฒจ ์ปฌ๋Ÿผ๋ช… + model_prediction_col (str): ๋ชจ๋ธ ์˜ˆ์ธก ์ปฌ๋Ÿผ๋ช… + eval_threshold (float): BERTScore ์œ ์‚ฌ๋„ ๊ธฐ์ค€ ์ž„๊ณ„๊ฐ’ + + Returns: + dict: ์ „์ฒด ํ‰๊ฐ€ ๋ฉ”ํŠธ๋ฆญ (metrics) + list: Confusion Matrix ๊ณ„์‚ฐ์„ ์œ„ํ•œ classification_data ([aspects_gold, aspects_pred, sentiments_gold, sentiments_pred]) + list: ํ‰๊ฐ€(BERTScore) ์œ ์‚ฌ๋„ ๋ฆฌ์ŠคํŠธ (eval_similarities) + """ + print("\n=== Step 1: Aggregate Evaluation ===") + metrics, classification_data, eval_similarities = aggregate_evaluation( + df, + golden_label_col=golden_label_col, + model_prediction_col=model_prediction_col, + eval_threshold=eval_threshold + ) + + print("\n=== Step 2: Compute Confusion Matrix and Classification Report ===") + compute_confusion_and_report( + df=df, + golden_label_col=golden_label_col, + model_prediction_col=model_prediction_col, + classification_data=classification_data + ) + + print("\n=== Step 3: Compute Evaluation Statistics (BERTScore Similarity) ===") + compute_eval_statistics(eval_similarities) diff --git a/models/review/utils/utils.py b/models/review/utils/utils.py new file mode 100644 index 0000000..8e5a006 --- /dev/null +++ b/models/review/utils/utils.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +[์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ๋ชจ๋“ˆ] +- ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ, ์ „์ฒ˜๋ฆฌ, ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ, UMAP, ํด๋Ÿฌ์Šคํ„ฐ๋ง, ์‹œ๊ฐํ™”, API ํ˜ธ์ถœ ๋“ฑ +""" + +import os +import numpy as np +import pandas as pd +import json +import requests +import time +import umap +import hdbscan +import matplotlib +matplotlib.use('Agg') +import matplotlib.pyplot as plt +from sklearn.cluster import AgglomerativeClustering +from sklearn.manifold import TSNE +from sklearn.metrics import silhouette_score, davies_bouldin_score +from sentence_transformers import SentenceTransformer +from dotenv import load_dotenv + +def load_data(file_path): + df = pd.read_csv(file_path) + print("๋ฐ์ดํ„ฐ ๋กœ๋“œ:", df.shape) + return df + +def load_and_preprocess_reviews(file_path): + df = pd.read_csv(file_path) + cols_to_fill = ["category", "name", "url", "meta"] + df[cols_to_fill] = df.groupby("ID")[cols_to_fill].transform(lambda x: x.ffill()) + meta_df = df[df["review-ID"].astype(str).str.endswith("-0")] + review_df = df[~df["review-ID"].astype(str).str.endswith("-0")] + return meta_df, review_df + +def expand_inference_data(df, json_column="unsloth_deepseek_32b"): + expanded = [] + for idx, row in df.iterrows(): + raw_value = row[json_column] + + # ๋งŒ์•ฝ raw_value๊ฐ€ ๋ฌธ์ž์—ด์ด๋ฉด json.loads()๋ฅผ ์‚ฌ์šฉ, ์ด๋ฏธ ๋ฆฌ์ŠคํŠธ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + if isinstance(raw_value, str): + try: + parsed = json.loads(raw_value) + except json.JSONDecodeError: + print(f"JSON ํŒŒ์‹ฑ ์—๋Ÿฌ, review-ID: {row.get('review-ID', 'N/A')}") + continue + elif isinstance(raw_value, list): + parsed = raw_value + else: + # ๊ทธ ์™ธ ํƒ€์ž…์ธ ๊ฒฝ์šฐ ๋ฌด์‹œ + continue + + if isinstance(parsed, list): + for item in parsed: + new_row = row.copy() + new_row["aspect"] = item.get("์†์„ฑ", None) + new_row["opinion"] = item.get("ํ‰๊ฐ€", None) + new_row["sentiment"] = item.get("๊ฐ์ •", None) + expanded.append(new_row) + expanded_df = pd.DataFrame(expanded) + expanded_df.reset_index(drop=True, inplace=True) + expanded_df.ffill(inplace=True) + return expanded_df + +def sentenceBERT_embeddings(embedding_path, df, column="processed", model_name="dragonkue/BGE-m3-ko"): + + print("\n์ž„๋ฒ ๋”ฉ ํŒŒ์ผ์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค...\n") + model = SentenceTransformer(model_name) + embeddings = df[column].apply(lambda txt: model.encode(txt, show_progress_bar=False)).tolist() + emb_matrix = np.array(embeddings) + np.save(embedding_path, emb_matrix) + print(f"\n์ž„๋ฒ ๋”ฉ ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {embedding_path}\n") + + print(f"์ž„๋ฒ ๋”ฉ Shape:{emb_matrix.shape}\n") + return emb_matrix + +def umap_reduce_embeddings(embedding_matrix, n_components=256, random_state=42): + num_samples, _ = embedding_matrix.shape + if n_components >= num_samples: + print("UMAP ์ ์šฉ ๋ถˆ๊ฐ€: n_components๊ฐ€ ๋ฐ์ดํ„ฐ ์ˆ˜๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค. ์›๋ณธ ๋ฐ˜ํ™˜.") + return embedding_matrix + reducer = umap.UMAP(n_components=n_components, random_state=random_state) + reduced = reducer.fit_transform(embedding_matrix) + print(f"์ฐจ์› ์ถ•์†Œ ์™„๋ฃŒ: {embedding_matrix.shape} -> {reduced.shape}") + return reduced + +def agglomerative_clustering(emb, distance_threshold=22.0, linkage="ward"): + clustering = AgglomerativeClustering(distance_threshold=distance_threshold, + n_clusters=None, + compute_full_tree=True, + linkage=linkage) + labels = clustering.fit_predict(emb) + print(f"Agglomerative Clustering ์™„๋ฃŒ: ํด๋Ÿฌ์Šคํ„ฐ ์ˆ˜ {np.unique(labels).shape[0]}") + return labels + +def visualize_clustering(emb, cluster_labels, config, category): + tsne = TSNE(n_components=2, perplexity=30, learning_rate=200, random_state=42) + emb_2d = tsne.fit_transform(emb) + plt.figure(figsize=(8, 6)) + sc = plt.scatter(emb_2d[:,0], emb_2d[:,1], c=cluster_labels, cmap="tab10", alpha=0.6) + plt.colorbar(sc, label="ํด๋Ÿฌ์Šคํ„ฐ ๋ฒˆํ˜ธ") + plt.title("Agglomerative Clustering Algorithm Visualization") + plt.xlabel("Component 1") + plt.ylabel("Component 2") + # plt.show() + plt.savefig(os.path.join(config["paths"]["embedding_dir"], f"{category}_cluster_result.png")) # ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ + + +def evaluate_clustering(emb, cluster_labels, config, category): + if len(set(cluster_labels)) > 1: + silhouette = silhouette_score(emb, cluster_labels) + dbi = davies_bouldin_score(emb, cluster_labels) + print(f"์‹ค๋ฃจ์—ฃ ์ ์ˆ˜: {silhouette:.4f}, Davies-Bouldin Index: {dbi:.4f}") + + results = {"category": category, "Silhouette": float(silhouette), "DBI": float(dbi)} + + json_path = os.path.join(config["paths"]["embedding_dir"], f"{category}_clustering_evaluation.json") + with open(json_path, "w") as f: + json.dump(results, f, indent=4) + + return results + else: + print("๋‹จ์ผ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ํ‰๊ฐ€ ๋ถˆ๊ฐ€") + return {"Silhouette": None, "DBI": None} diff --git a/models/size_description/README.md b/models/size_description/README.md new file mode 100644 index 0000000..0720ac0 --- /dev/null +++ b/models/size_description/README.md @@ -0,0 +1,40 @@ +# ์ œํ’ˆ ํฌ๊ธฐ ๊ฐ์ง€ ๋ฐ ๋น„๊ต +- ๋ณธ ํ”„๋กœ์ ํŠธ๋Š” YOLO ๊ธฐ๋ฐ˜์˜ Object Detection ๊ธฐ๋ฒ•์„ ํ™œ์šฉํ•˜์—ฌ ์ œํ’ˆ์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ œํ’ˆ ๊ฐ„ ํฌ๊ธฐ ๋น„๊ต ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. +- ํ•™์Šต ๋ฐ์ดํ„ฐ์— ๊ธฐ๋ฐ˜ํ•œ ๋ชจ๋ธ ๋ผ๋ฒจ๋ง ๋ฐ ํ•™์Šต ๊ณผ์ •์„ ๊ฑฐ์ณ, ์‹ค์ œ ์ธํผ๋Ÿฐ์Šค ๋‹จ๊ณ„์—์„œ๋Š” ์ž…๋ ฅ ์ด๋ฏธ์ง€์—์„œ ์ œํ’ˆ์˜ ํฌ๊ธฐ๋ฅผ ์ž๋™์œผ๋กœ ์ธก์ •ํ•˜๊ณ  ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## ์ฃผ์š” ํŠน์ง• +1. **YOLO ๋ชจ๋ธ ํ™œ์šฉ**: YOLO Object Detection์„ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ œํ’ˆ์˜ ์œ„์น˜์™€ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค. +2. **๋ชจ๋ธ ๋ผ๋ฒจ๋ง ๋ฐ ํ•™์Šต**: `data/train` ํด๋” ๋‚ด ๋‹ค์ˆ˜์˜ annotation ํŒŒ์ผ(์˜ˆ: `mall-101-3.txt`, `mall-106-3.txt` ๋“ฑ)์„ ํ™œ์šฉํ•ด ๋ชจ๋ธ์„ ํ•™์Šตํ•ฉ๋‹ˆ๋‹ค. +3. **์ œํ’ˆ ํฌ๊ธฐ ์ธก์ •**: ํ•™์Šต๋œ ๋ชจ๋ธ์„ ํ†ตํ•ด ์ด๋ฏธ์ง€ ๋‚ด ์ œํ’ˆ์˜ ํฌ๊ธฐ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ์ง€ ๋ฐ ์ธก์ •ํ•ฉ๋‹ˆ๋‹ค. +4. **ํฌ๊ธฐ ๋น„๊ต ๊ธฐ๋Šฅ**: ๊ฐ์ง€๋œ ํฌ๊ธฐ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—ฌ๋Ÿฌ ์ œํ’ˆ ๊ฐ„์˜ ํฌ๊ธฐ๋ฅผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + +## ํด๋” ๊ตฌ์กฐ +```bash +. +โ”œโ”€โ”€ data +โ”‚ โ””โ”€โ”€ train +โ”œโ”€โ”€ size_info.yaml +โ””โ”€โ”€ src + โ”œโ”€โ”€ inference.py + โ””โ”€โ”€ train.py +``` + +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• +### 1) ํ™˜๊ฒฝ ๊ตฌ์ถ• +- Python 3.11.11 ๋ฒ„์ „ ๊ถŒ์žฅ +- ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜: `pip install -r requirements.txt` + +### 2) ๋ฐ์ดํ„ฐ ์ค€๋น„ +- ํ•™์Šต ๋ฐ์ดํ„ฐ + - data/train ํด๋”์— ํ•™์Šต์šฉ ์ด๋ฏธ์ง€ ๋ฐ ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” annotation ํŒŒ์ผ๊ณผ classes.txt๋ฅผ ์œ„์น˜์‹œํ‚ต๋‹ˆ๋‹ค. + - ๊ฐ ํ…์ŠคํŠธ ํŒŒ์ผ์—๋Š” ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ๊ฐ์ฒด ์ขŒํ‘œ ๋ฐ ํด๋ž˜์Šค ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. + +### 3) ์‹คํ–‰ ๋ฐฉ๋ฒ• +- ๋ชจ๋ธ ํ•™์Šต + - ํ•™์Šต ์Šคํฌ๋ฆฝํŠธ๋Š” src/train.py์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ•™์Šต์— ํ•„์š”ํ•œ ํ•˜์ดํผํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜ ๊ธฐํƒ€ ์˜ต์…˜์€ ์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ธ์ž๊ฐ’์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +```python src/train.py``` + +- ์ธํผ๋Ÿฐ์Šค + - ํ•™์Šต๋œ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€ ์ƒ์˜ ์ œํ’ˆ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง€ ๋ฐ ๋น„๊ตํ•˜๋ ค๋ฉด src/inference.py ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + - ์ธํผ๋Ÿฐ์Šค ์‹คํ–‰ ์‹œ, ์ž…๋ ฅ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ๋“ฑ ํ•„์š”ํ•œ ์ธ์ž๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +```python src/inference.py --image <์ด๋ฏธ์ง€_๊ฒฝ๋กœ>``` \ No newline at end of file diff --git a/models/size_description/data/train/classes.txt b/models/size_description/data/train/classes.txt new file mode 100644 index 0000000..0c690fa --- /dev/null +++ b/models/size_description/data/train/classes.txt @@ -0,0 +1,4 @@ +product +compare_pet +compare_can +compare_cup diff --git a/models/size_description/data/train/mall-101-3.txt b/models/size_description/data/train/mall-101-3.txt new file mode 100644 index 0000000..dc27369 --- /dev/null +++ b/models/size_description/data/train/mall-101-3.txt @@ -0,0 +1,2 @@ +0 0.362760 0.529948 0.502604 0.450521 +2 0.768490 0.513021 0.183854 0.475000 diff --git a/models/size_description/data/train/mall-106-3.txt b/models/size_description/data/train/mall-106-3.txt new file mode 100644 index 0000000..025e30d --- /dev/null +++ b/models/size_description/data/train/mall-106-3.txt @@ -0,0 +1,2 @@ +0 0.375333 0.531333 0.444000 0.524000 +1 0.717333 0.514000 0.176000 0.553333 diff --git a/models/size_description/data/train/mall-108-4.txt b/models/size_description/data/train/mall-108-4.txt new file mode 100644 index 0000000..b51e68d --- /dev/null +++ b/models/size_description/data/train/mall-108-4.txt @@ -0,0 +1 @@ +0 0.436667 0.472667 0.785333 0.788000 diff --git a/models/size_description/data/train/mall-111-3.txt b/models/size_description/data/train/mall-111-3.txt new file mode 100644 index 0000000..8fcdf35 --- /dev/null +++ b/models/size_description/data/train/mall-111-3.txt @@ -0,0 +1,2 @@ +0 0.342000 0.546000 0.481333 0.206667 +3 0.761333 0.519333 0.240000 0.260000 diff --git a/models/size_description/data/train/mall-117-3.txt b/models/size_description/data/train/mall-117-3.txt new file mode 100644 index 0000000..2e7b284 --- /dev/null +++ b/models/size_description/data/train/mall-117-3.txt @@ -0,0 +1,2 @@ +0 0.334375 0.502344 0.387500 0.766146 +1 0.704948 0.543750 0.206771 0.673958 diff --git a/models/size_description/data/train/mall-121-3.txt b/models/size_description/data/train/mall-121-3.txt new file mode 100644 index 0000000..98b7766 --- /dev/null +++ b/models/size_description/data/train/mall-121-3.txt @@ -0,0 +1,2 @@ +0 0.340667 0.501333 0.286667 0.800000 +1 0.655333 0.545333 0.220000 0.714667 diff --git a/models/size_description/data/train/mall-125-2.txt b/models/size_description/data/train/mall-125-2.txt new file mode 100644 index 0000000..ca4c522 --- /dev/null +++ b/models/size_description/data/train/mall-125-2.txt @@ -0,0 +1,2 @@ +0 0.364063 0.528906 0.373958 0.571354 +1 0.683594 0.529687 0.173437 0.557292 diff --git a/models/size_description/data/train/mall-126-5.txt b/models/size_description/data/train/mall-126-5.txt new file mode 100644 index 0000000..f64f6af --- /dev/null +++ b/models/size_description/data/train/mall-126-5.txt @@ -0,0 +1,2 @@ +0 0.394000 0.500667 0.588000 0.412000 +2 0.810667 0.532667 0.136000 0.345333 diff --git a/models/size_description/data/train/mall-135-4.txt b/models/size_description/data/train/mall-135-4.txt new file mode 100644 index 0000000..7c26232 --- /dev/null +++ b/models/size_description/data/train/mall-135-4.txt @@ -0,0 +1,2 @@ +0 0.362240 0.520052 0.186979 0.675521 +1 0.575781 0.518490 0.206771 0.672396 diff --git a/models/size_description/data/train/mall-137-4.txt b/models/size_description/data/train/mall-137-4.txt new file mode 100644 index 0000000..0b1c133 --- /dev/null +++ b/models/size_description/data/train/mall-137-4.txt @@ -0,0 +1,2 @@ +0 0.396000 0.501333 0.584000 0.466667 +2 0.804667 0.555333 0.142667 0.369333 diff --git a/models/size_description/data/train/mall-144-2.txt b/models/size_description/data/train/mall-144-2.txt new file mode 100644 index 0000000..8701419 --- /dev/null +++ b/models/size_description/data/train/mall-144-2.txt @@ -0,0 +1,2 @@ +0 0.387240 0.546615 0.333854 0.324479 +2 0.676562 0.509635 0.153125 0.392188 diff --git a/models/size_description/data/train/mall-151-3.txt b/models/size_description/data/train/mall-151-3.txt new file mode 100644 index 0000000..318c741 --- /dev/null +++ b/models/size_description/data/train/mall-151-3.txt @@ -0,0 +1,4 @@ +0 0.161333 0.572667 0.090667 0.188000 +3 0.286000 0.597333 0.105333 0.130667 +0 0.568667 0.523333 0.350667 0.278667 +2 0.842667 0.510667 0.114667 0.298667 diff --git a/models/size_description/data/train/mall-152-3.txt b/models/size_description/data/train/mall-152-3.txt new file mode 100644 index 0000000..27bec42 --- /dev/null +++ b/models/size_description/data/train/mall-152-3.txt @@ -0,0 +1,2 @@ +0 0.332667 0.524667 0.478667 0.636000 +1 0.736667 0.501333 0.212000 0.677333 diff --git a/models/size_description/data/train/mall-153-2.txt b/models/size_description/data/train/mall-153-2.txt new file mode 100644 index 0000000..e6eb999 --- /dev/null +++ b/models/size_description/data/train/mall-153-2.txt @@ -0,0 +1,2 @@ +0 0.385677 0.529687 0.193229 0.407292 +2 0.644531 0.512760 0.174479 0.444271 diff --git a/models/size_description/data/train/mall-165-5.txt b/models/size_description/data/train/mall-165-5.txt new file mode 100644 index 0000000..7f0f34d --- /dev/null +++ b/models/size_description/data/train/mall-165-5.txt @@ -0,0 +1,2 @@ +0 0.343333 0.546667 0.476000 0.642667 +1 0.746667 0.520000 0.218667 0.698667 diff --git a/models/size_description/data/train/mall-167-3.txt b/models/size_description/data/train/mall-167-3.txt new file mode 100644 index 0000000..01f6726 --- /dev/null +++ b/models/size_description/data/train/mall-167-3.txt @@ -0,0 +1,2 @@ +0 0.415885 0.499219 0.134896 0.477604 +2 0.613281 0.542708 0.150521 0.387500 diff --git a/models/size_description/data/train/mall-192-3.txt b/models/size_description/data/train/mall-192-3.txt new file mode 100644 index 0000000..8edf418 --- /dev/null +++ b/models/size_description/data/train/mall-192-3.txt @@ -0,0 +1,2 @@ +0 0.338281 0.519010 0.554688 0.695312 +1 0.781510 0.522656 0.209896 0.678646 diff --git a/models/size_description/data/train/mall-201-5.txt b/models/size_description/data/train/mall-201-5.txt new file mode 100644 index 0000000..33efb9c --- /dev/null +++ b/models/size_description/data/train/mall-201-5.txt @@ -0,0 +1,2 @@ +0 0.387333 0.565333 0.577333 0.392000 +1 0.790000 0.513333 0.148000 0.496000 diff --git a/models/size_description/data/train/mall-203-4.txt b/models/size_description/data/train/mall-203-4.txt new file mode 100644 index 0000000..3faa09a --- /dev/null +++ b/models/size_description/data/train/mall-203-4.txt @@ -0,0 +1,2 @@ +0 0.403333 0.514000 0.588000 0.441333 +1 0.800000 0.513333 0.136000 0.448000 diff --git a/models/size_description/data/train/mall-222-3.txt b/models/size_description/data/train/mall-222-3.txt new file mode 100644 index 0000000..cf26d8f --- /dev/null +++ b/models/size_description/data/train/mall-222-3.txt @@ -0,0 +1,2 @@ +0 0.398698 0.493750 0.583854 0.816667 +1 0.783854 0.659375 0.146875 0.485417 diff --git a/models/size_description/data/train/mall-24-3.txt b/models/size_description/data/train/mall-24-3.txt new file mode 100644 index 0000000..8075dbe --- /dev/null +++ b/models/size_description/data/train/mall-24-3.txt @@ -0,0 +1,2 @@ +0 0.396354 0.526823 0.579167 0.542188 +1 0.805469 0.528125 0.168229 0.530208 diff --git a/models/size_description/data/train/mall-242-2.txt b/models/size_description/data/train/mall-242-2.txt new file mode 100644 index 0000000..132660e --- /dev/null +++ b/models/size_description/data/train/mall-242-2.txt @@ -0,0 +1,2 @@ +0 0.365625 0.510677 0.429167 0.727604 +1 0.752344 0.539062 0.206771 0.667708 diff --git a/models/size_description/data/train/mall-243-3.txt b/models/size_description/data/train/mall-243-3.txt new file mode 100644 index 0000000..78480e3 --- /dev/null +++ b/models/size_description/data/train/mall-243-3.txt @@ -0,0 +1,2 @@ +0 0.348177 0.521354 0.509896 0.669792 +1 0.750000 0.519792 0.211458 0.672917 diff --git a/models/size_description/data/train/mall-249-2.txt b/models/size_description/data/train/mall-249-2.txt new file mode 100644 index 0000000..2bcdaaf --- /dev/null +++ b/models/size_description/data/train/mall-249-2.txt @@ -0,0 +1,2 @@ +0 0.388021 0.548177 0.504167 0.502604 +1 0.769271 0.516146 0.176042 0.563542 diff --git a/models/size_description/data/train/mall-256-3.txt b/models/size_description/data/train/mall-256-3.txt new file mode 100644 index 0000000..a1bf234 --- /dev/null +++ b/models/size_description/data/train/mall-256-3.txt @@ -0,0 +1,2 @@ +0 0.367448 0.528125 0.438021 0.673958 +1 0.755469 0.535677 0.200521 0.652604 diff --git a/models/size_description/data/train/mall-266-2.txt b/models/size_description/data/train/mall-266-2.txt new file mode 100644 index 0000000..5d10d1b --- /dev/null +++ b/models/size_description/data/train/mall-266-2.txt @@ -0,0 +1,2 @@ +0 0.384115 0.503906 0.428646 0.652604 +1 0.746354 0.517448 0.194792 0.616146 diff --git a/models/size_description/data/train/mall-267-2.txt b/models/size_description/data/train/mall-267-2.txt new file mode 100644 index 0000000..86f60eb --- /dev/null +++ b/models/size_description/data/train/mall-267-2.txt @@ -0,0 +1,2 @@ +0 0.382552 0.526042 0.496354 0.497917 +1 0.744792 0.514583 0.166667 0.520833 diff --git a/models/size_description/data/train/mall-27-2.txt b/models/size_description/data/train/mall-27-2.txt new file mode 100644 index 0000000..aaf5619 --- /dev/null +++ b/models/size_description/data/train/mall-27-2.txt @@ -0,0 +1,2 @@ +0 0.367448 0.501563 0.232813 0.712500 +1 0.652083 0.519271 0.211458 0.680208 diff --git a/models/size_description/data/train/mall-272-2.txt b/models/size_description/data/train/mall-272-2.txt new file mode 100644 index 0000000..5efbdfa --- /dev/null +++ b/models/size_description/data/train/mall-272-2.txt @@ -0,0 +1,2 @@ +0 0.397917 0.499219 0.306250 0.196354 +3 0.669792 0.513802 0.139583 0.164062 diff --git a/models/size_description/data/train/mall-273-3.txt b/models/size_description/data/train/mall-273-3.txt new file mode 100644 index 0000000..7d5fb7c --- /dev/null +++ b/models/size_description/data/train/mall-273-3.txt @@ -0,0 +1,2 @@ +0 0.358333 0.551302 0.163542 0.539062 +1 0.606510 0.490885 0.206771 0.672396 diff --git a/models/size_description/data/train/mall-274-2.txt b/models/size_description/data/train/mall-274-2.txt new file mode 100644 index 0000000..0b5fa69 --- /dev/null +++ b/models/size_description/data/train/mall-274-2.txt @@ -0,0 +1,2 @@ +0 0.334667 0.569333 0.184000 0.570667 +1 0.645333 0.514667 0.210667 0.685333 diff --git a/models/size_description/data/train/mall-275-3.txt b/models/size_description/data/train/mall-275-3.txt new file mode 100644 index 0000000..d4be780 --- /dev/null +++ b/models/size_description/data/train/mall-275-3.txt @@ -0,0 +1,2 @@ +0 0.307333 0.498667 0.422667 0.373333 +3 0.729333 0.530000 0.296000 0.316000 diff --git a/models/size_description/data/train/mall-28-3.txt b/models/size_description/data/train/mall-28-3.txt new file mode 100644 index 0000000..543ba14 --- /dev/null +++ b/models/size_description/data/train/mall-28-3.txt @@ -0,0 +1,2 @@ +0 0.353333 0.516667 0.488000 0.489333 +2 0.772667 0.514000 0.190667 0.494667 diff --git a/models/size_description/data/train/mall-280-5.txt b/models/size_description/data/train/mall-280-5.txt new file mode 100644 index 0000000..463c7cb --- /dev/null +++ b/models/size_description/data/train/mall-280-5.txt @@ -0,0 +1,2 @@ +0 0.343333 0.502000 0.478667 0.646667 +2 0.759333 0.552667 0.214667 0.548000 diff --git a/models/size_description/data/train/mall-281-3.txt b/models/size_description/data/train/mall-281-3.txt new file mode 100644 index 0000000..08d2d13 --- /dev/null +++ b/models/size_description/data/train/mall-281-3.txt @@ -0,0 +1,2 @@ +0 0.395052 0.495312 0.225521 0.678125 +2 0.666927 0.595573 0.183854 0.477604 diff --git a/models/size_description/data/train/mall-282-3.txt b/models/size_description/data/train/mall-282-3.txt new file mode 100644 index 0000000..cbe262e --- /dev/null +++ b/models/size_description/data/train/mall-282-3.txt @@ -0,0 +1,2 @@ +0 0.376302 0.500000 0.483854 0.332292 +3 0.735677 0.552083 0.206771 0.237500 diff --git a/models/size_description/data/train/mall-285-3.txt b/models/size_description/data/train/mall-285-3.txt new file mode 100644 index 0000000..1e66fe8 --- /dev/null +++ b/models/size_description/data/train/mall-285-3.txt @@ -0,0 +1,2 @@ +0 0.384115 0.575781 0.459896 0.269271 +2 0.743490 0.509635 0.154688 0.392188 diff --git a/models/size_description/data/train/mall-286-3.txt b/models/size_description/data/train/mall-286-3.txt new file mode 100644 index 0000000..0ba4879 --- /dev/null +++ b/models/size_description/data/train/mall-286-3.txt @@ -0,0 +1,2 @@ +0 0.321333 0.552000 0.442667 0.226667 +3 0.739333 0.522000 0.276000 0.297333 diff --git a/models/size_description/data/train/mall-287-3.txt b/models/size_description/data/train/mall-287-3.txt new file mode 100644 index 0000000..49d360c --- /dev/null +++ b/models/size_description/data/train/mall-287-3.txt @@ -0,0 +1,2 @@ +0 0.310667 0.500000 0.429333 0.368000 +3 0.735333 0.529333 0.294667 0.312000 diff --git a/models/size_description/data/train/mall-288-3.txt b/models/size_description/data/train/mall-288-3.txt new file mode 100644 index 0000000..fb4f2be --- /dev/null +++ b/models/size_description/data/train/mall-288-3.txt @@ -0,0 +1,2 @@ +0 0.339333 0.496667 0.486667 0.390667 +3 0.758000 0.559333 0.249333 0.268000 diff --git a/models/size_description/data/train/mall-290-4.txt b/models/size_description/data/train/mall-290-4.txt new file mode 100644 index 0000000..c525bdb --- /dev/null +++ b/models/size_description/data/train/mall-290-4.txt @@ -0,0 +1,2 @@ +0 0.308667 0.514000 0.428000 0.326667 +3 0.733333 0.523333 0.296000 0.310667 diff --git a/models/size_description/data/train/mall-293-2.txt b/models/size_description/data/train/mall-293-2.txt new file mode 100644 index 0000000..1e5b6c2 --- /dev/null +++ b/models/size_description/data/train/mall-293-2.txt @@ -0,0 +1,2 @@ +0 0.385677 0.575000 0.410938 0.264583 +2 0.718750 0.512760 0.148958 0.392188 diff --git a/models/size_description/data/train/mall-295-3.txt b/models/size_description/data/train/mall-295-3.txt new file mode 100644 index 0000000..1272168 --- /dev/null +++ b/models/size_description/data/train/mall-295-3.txt @@ -0,0 +1,2 @@ +0 0.404167 0.497396 0.214583 0.205208 +3 0.619271 0.514583 0.139583 0.165625 diff --git a/models/size_description/data/train/mall-302-2.txt b/models/size_description/data/train/mall-302-2.txt new file mode 100644 index 0000000..623385c --- /dev/null +++ b/models/size_description/data/train/mall-302-2.txt @@ -0,0 +1,2 @@ +0 0.390104 0.496875 0.300000 0.197917 +3 0.670573 0.513021 0.141146 0.168750 diff --git a/models/size_description/data/train/mall-303-3.txt b/models/size_description/data/train/mall-303-3.txt new file mode 100644 index 0000000..19aedac --- /dev/null +++ b/models/size_description/data/train/mall-303-3.txt @@ -0,0 +1,2 @@ +0 0.365104 0.500000 0.133333 0.338542 +3 0.576302 0.545833 0.203646 0.240625 diff --git a/models/size_description/data/train/mall-311-2.txt b/models/size_description/data/train/mall-311-2.txt new file mode 100644 index 0000000..2733ef9 --- /dev/null +++ b/models/size_description/data/train/mall-311-2.txt @@ -0,0 +1,2 @@ +0 0.392448 0.496875 0.151562 0.537500 +2 0.584115 0.572656 0.160938 0.392188 diff --git a/models/size_description/data/train/mall-317-3.txt b/models/size_description/data/train/mall-317-3.txt new file mode 100644 index 0000000..0c7092c --- /dev/null +++ b/models/size_description/data/train/mall-317-3.txt @@ -0,0 +1,2 @@ +0 0.381771 0.502865 0.319792 0.213021 +3 0.693490 0.515104 0.177604 0.188542 diff --git a/models/size_description/data/train/mall-327-2.txt b/models/size_description/data/train/mall-327-2.txt new file mode 100644 index 0000000..6fb7e1e --- /dev/null +++ b/models/size_description/data/train/mall-327-2.txt @@ -0,0 +1,2 @@ +0 0.356771 0.569010 0.148958 0.678646 +1 0.625000 0.522135 0.234375 0.772396 diff --git a/models/size_description/data/train/mall-332-5.txt b/models/size_description/data/train/mall-332-5.txt new file mode 100644 index 0000000..aad1831 --- /dev/null +++ b/models/size_description/data/train/mall-332-5.txt @@ -0,0 +1,2 @@ +0 0.334667 0.496667 0.448000 0.670667 +2 0.751333 0.555333 0.228000 0.580000 diff --git a/models/size_description/data/train/mall-354-2.txt b/models/size_description/data/train/mall-354-2.txt new file mode 100644 index 0000000..3914f33 --- /dev/null +++ b/models/size_description/data/train/mall-354-2.txt @@ -0,0 +1,2 @@ +0 0.366406 0.523698 0.519271 0.284896 +3 0.787760 0.567969 0.173437 0.186979 diff --git a/models/size_description/data/train/mall-357-4.txt b/models/size_description/data/train/mall-357-4.txt new file mode 100644 index 0000000..a8a482f --- /dev/null +++ b/models/size_description/data/train/mall-357-4.txt @@ -0,0 +1,2 @@ +0 0.363333 0.552667 0.526667 0.385333 +2 0.779333 0.512667 0.182667 0.470667 diff --git a/models/size_description/data/train/mall-364-3.txt b/models/size_description/data/train/mall-364-3.txt new file mode 100644 index 0000000..b711ead --- /dev/null +++ b/models/size_description/data/train/mall-364-3.txt @@ -0,0 +1,2 @@ +0 0.400260 0.498177 0.353646 0.464062 +2 0.702604 0.537240 0.153125 0.389062 diff --git a/models/size_description/data/train/mall-366-4.txt b/models/size_description/data/train/mall-366-4.txt new file mode 100644 index 0000000..8635a32 --- /dev/null +++ b/models/size_description/data/train/mall-366-4.txt @@ -0,0 +1,2 @@ +0 0.386458 0.536719 0.504167 0.396354 +2 0.771615 0.496094 0.183854 0.471354 diff --git a/models/size_description/data/train/mall-371-2.txt b/models/size_description/data/train/mall-371-2.txt new file mode 100644 index 0000000..eeb2ba3 --- /dev/null +++ b/models/size_description/data/train/mall-371-2.txt @@ -0,0 +1,2 @@ +0 0.369531 0.575000 0.445312 0.562500 +1 0.752344 0.516146 0.209896 0.680208 diff --git a/models/size_description/data/train/mall-375-3.txt b/models/size_description/data/train/mall-375-3.txt new file mode 100644 index 0000000..1014c91 --- /dev/null +++ b/models/size_description/data/train/mall-375-3.txt @@ -0,0 +1,2 @@ +0 0.353385 0.495312 0.303646 0.660417 +2 0.639062 0.585677 0.182292 0.470313 diff --git a/models/size_description/data/train/mall-379-3.txt b/models/size_description/data/train/mall-379-3.txt new file mode 100644 index 0000000..a460f3e --- /dev/null +++ b/models/size_description/data/train/mall-379-3.txt @@ -0,0 +1,2 @@ +0 0.391927 0.553385 0.604688 0.310937 +2 0.806250 0.509115 0.153125 0.393229 diff --git a/models/size_description/data/train/mall-41-3.txt b/models/size_description/data/train/mall-41-3.txt new file mode 100644 index 0000000..97b9396 --- /dev/null +++ b/models/size_description/data/train/mall-41-3.txt @@ -0,0 +1,2 @@ +0 0.372656 0.505208 0.503646 0.692708 +1 0.754167 0.562760 0.185417 0.590104 diff --git a/models/size_description/data/train/mall-44-2.txt b/models/size_description/data/train/mall-44-2.txt new file mode 100644 index 0000000..3a9f837 --- /dev/null +++ b/models/size_description/data/train/mall-44-2.txt @@ -0,0 +1,2 @@ +0 0.395573 0.500521 0.405729 0.514583 +2 0.730990 0.565625 0.154688 0.387500 diff --git a/models/size_description/data/train/mall-52-3.txt b/models/size_description/data/train/mall-52-3.txt new file mode 100644 index 0000000..30a2293 --- /dev/null +++ b/models/size_description/data/train/mall-52-3.txt @@ -0,0 +1,2 @@ +0 0.369531 0.514583 0.240104 0.481250 +2 0.650781 0.530729 0.174479 0.439583 diff --git a/models/size_description/data/train/mall-54-3.txt b/models/size_description/data/train/mall-54-3.txt new file mode 100644 index 0000000..de09b70 --- /dev/null +++ b/models/size_description/data/train/mall-54-3.txt @@ -0,0 +1,2 @@ +0 0.394792 0.579427 0.407292 0.255729 +2 0.731771 0.512760 0.153125 0.385937 diff --git a/models/size_description/data/train/mall-56-3.txt b/models/size_description/data/train/mall-56-3.txt new file mode 100644 index 0000000..35f1999 --- /dev/null +++ b/models/size_description/data/train/mall-56-3.txt @@ -0,0 +1,2 @@ +0 0.392000 0.565333 0.581333 0.426667 +1 0.815333 0.493333 0.180000 0.573333 diff --git a/models/size_description/data/train/mall-59-3.txt b/models/size_description/data/train/mall-59-3.txt new file mode 100644 index 0000000..d1cab61 --- /dev/null +++ b/models/size_description/data/train/mall-59-3.txt @@ -0,0 +1,2 @@ +0 0.378906 0.490625 0.214062 0.644792 +2 0.651823 0.575781 0.183854 0.474479 diff --git a/models/size_description/data/train/mall-77-3.txt b/models/size_description/data/train/mall-77-3.txt new file mode 100644 index 0000000..c9310a8 --- /dev/null +++ b/models/size_description/data/train/mall-77-3.txt @@ -0,0 +1,2 @@ +0 0.418000 0.503333 0.641333 0.441333 +2 0.854000 0.548000 0.137333 0.352000 diff --git a/models/size_description/data/train/mall-83-3.txt b/models/size_description/data/train/mall-83-3.txt new file mode 100644 index 0000000..3459476 --- /dev/null +++ b/models/size_description/data/train/mall-83-3.txt @@ -0,0 +1,2 @@ +0 0.366406 0.489844 0.301563 0.643229 +2 0.655990 0.577344 0.184896 0.477604 diff --git a/models/size_description/data/train/mall-87-3.txt b/models/size_description/data/train/mall-87-3.txt new file mode 100644 index 0000000..6f8faa0 --- /dev/null +++ b/models/size_description/data/train/mall-87-3.txt @@ -0,0 +1,2 @@ +0 0.371875 0.523698 0.422917 0.613021 +1 0.725000 0.516667 0.182292 0.602083 diff --git a/models/size_description/data/train/mall-88-5.txt b/models/size_description/data/train/mall-88-5.txt new file mode 100644 index 0000000..bc2db02 --- /dev/null +++ b/models/size_description/data/train/mall-88-5.txt @@ -0,0 +1,2 @@ +0 0.326000 0.497333 0.438667 0.624000 +2 0.746667 0.519333 0.234667 0.604000 diff --git a/models/size_description/data/train/mall-98-3.txt b/models/size_description/data/train/mall-98-3.txt new file mode 100644 index 0000000..9568440 --- /dev/null +++ b/models/size_description/data/train/mall-98-3.txt @@ -0,0 +1,2 @@ +0 0.290667 0.500667 0.392000 0.398667 +3 0.716667 0.532000 0.313333 0.338667 diff --git a/models/size_description/size_info.yaml b/models/size_description/size_info.yaml new file mode 100644 index 0000000..ac1fdff --- /dev/null +++ b/models/size_description/size_info.yaml @@ -0,0 +1,10 @@ +# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] +train: train # train images (relative to 'path') 128 images +val: train # val images (relative to 'path') 128 images +# test: # test images (optional) + +names: + 0: product + 1: compare_pet + 2: compare_beer + 3: compare_cup diff --git a/models/size_description/src/inference.py b/models/size_description/src/inference.py new file mode 100644 index 0000000..52ec601 --- /dev/null +++ b/models/size_description/src/inference.py @@ -0,0 +1,173 @@ +import requests +from io import BytesIO +import pandas as pd +from PIL import Image + +from ultralytics import YOLO + + +compare_actual_sizes = { + 1: {"name": "2L ํŽ˜ํŠธ๋ณ‘", "width_cm": 9.0, "height_cm": 31.0}, + 2: {"name": "500ml ์บ”", "width_cm": 6.5, "height_cm": 16.5}, + 3: {"name": "์ข…์ด์ปต", "width_cm": 7.0, "height_cm": 7.5} +} + + +def download_image(url): + response = requests.get(url) + response.raise_for_status() # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + return Image.open(BytesIO(response.content)) + + +def get_detection_from_image(image_dir, model_path, show=False): + model = YOLO(model_path) + image = None + + if image_dir.startswith("https"): + image = download_image(image_dir) + else: + image = Image.open(image_dir) + results = model(image, conf=0.3) + + if show: + # ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” ๋ฐ ์ €์žฅ + for idx, result in enumerate(results): + result.show() + + # ๊ฐ์ง€๋œ ๊ฐ์ฒด ์ •๋ณด ์ถœ๋ ฅ + for result in results: + print("Bounding Boxes:", result.boxes.xyxy) + print("Class IDs:", result.boxes.cls) + print("Confidence Scores:", result.boxes.conf) + + return results + + +def process_result_with_actual_size_desc(result): + boxes = result.boxes.xyxy + classes = result.boxes.cls + + # product(0) ํ›„๋ณด์™€ compare(1,2,3) ํ›„๋ณด๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์ €์žฅ + product_candidates = [] # (box) + compare_candidates = [] # (box, class_id) + + for box, cls_id in zip(boxes, classes): + cls_id_int = int(cls_id.item()) # ํด๋ž˜์Šค ID๋ฅผ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ + if cls_id_int == 0: # product + product_candidates.append(box) + elif cls_id_int in [1, 2, 3]: # compare + compare_candidates.append((box, cls_id_int)) + + # ๋งŒ์•ฝ product๋‚˜ compare ํ›„๋ณด๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค๋ฉด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + if not product_candidates: + print("product(0) ํด๋ž˜์Šค ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + if not compare_candidates: + print("compare(1,2,3) ํด๋ž˜์Šค ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + + # product ์ค‘์—์„œ x2(์˜ค๋ฅธ์ชฝ) ์ขŒํ‘œ๊ฐ€ ๊ฐ€์žฅ ํฐ ๋ฐ•์Šค ํ•˜๋‚˜ ์„ ํƒ + selected_product_box = max(product_candidates, key=lambda b: b[2].item()) + + # compare(1,2,3) ์ค‘์—์„œ x2(์˜ค๋ฅธ์ชฝ) ์ขŒํ‘œ๊ฐ€ ๊ฐ€์žฅ ํฐ ๋ฐ•์Šค๊ณผ ๊ทธ ํด๋ž˜์Šค ID๋ฅผ ํ•˜๋‚˜ ์„ ํƒ + selected_compare_box, selected_compare_class = max(compare_candidates, key=lambda x: x[0][2].item()) + + global compare_actual_sizes + + compare_info = compare_actual_sizes.get(selected_compare_class) + if not compare_info: + print("์•Œ ์ˆ˜ ์—†๋Š” ๋น„๊ต ๋Œ€์ƒ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.") + return + + compare_name = compare_info["name"] + + compare_actual_width = compare_info["width_cm"] + compare_actual_height = compare_info["height_cm"] + + compare_pixel_width = selected_compare_box[2].item() - selected_compare_box[0].item() + compare_pixel_height = selected_compare_box[3].item() - selected_compare_box[1].item() + + scale_width = compare_actual_width / compare_pixel_width + scale_height = compare_actual_height / compare_pixel_height + + product_pixel_width = selected_product_box[2].item() - selected_product_box[0].item() + product_pixel_height = selected_product_box[3].item() - selected_product_box[1].item() + + product_actual_width = product_pixel_width * scale_width + product_actual_height = product_pixel_height * scale_height + + width_ratio = product_actual_width / compare_actual_width + height_ratio = product_actual_height / compare_actual_height + + def describe_ratio_first(ratio, compare_name, dimension): + ratio = round(ratio, 3) + base_text = f"{compare_name} {dimension}" + + # ์ •์ˆ˜์™€ ๊ฐ™์€์ง€ ์ฒดํฌ + if float(int(ratio)) == float(ratio): + if ratio == 1: + return f"{base_text}์™€ ๊ฐ™๊ณ " + return f"{base_text}์˜ {int(ratio)}๋ฐฐ์ด๊ณ " + + if ratio > 1.5: + # ๋ฐ˜์˜ฌ๋ฆผ ํ•œํ›„, ์˜ฌ๋ฆผ์ด๋ฉด ํฌ๋‹ค, ๋‚ด๋ฆผ์ด๋ฉด ์ž‘๋‹ค ํ‘œ์‹œ + rounded_ratio = round(ratio) + if rounded_ratio > ratio: # 2.0 > 1.9 + return f"{base_text}์˜ {rounded_ratio}๋ฐฐ๋ณด๋‹ค ์กฐ๊ธˆ ์ž‘๊ณ " + if rounded_ratio < ratio: # 2.0 < 2.2 + return f"{base_text}์˜ {rounded_ratio}๋ฐฐ๋ณด๋‹ค ์กฐ๊ธˆ ํฌ๊ณ " + if ratio > 1.0: + return f"{base_text}๋ณด๋‹ค ์กฐ๊ธˆ ํฌ๊ณ " + if 0.5 <= ratio < 1.0: + return f"{base_text}๋ณด๋‹ค ์กฐ๊ธˆ ์ž‘๊ณ " + return f"{base_text}๋ณด๋‹ค ๋ฐ˜ ์ด์ƒ ์ž‘๊ณ " + + def describe_ratio(ratio, compare_name, dimension): + ratio = round(ratio, 3) + base_text = f"{compare_name} {dimension}" + + # ์ •์ˆ˜์™€ ๊ฐ™์€์ง€ ์ฒดํฌ + if float(int(ratio)) == float(ratio): + if ratio == 1: + return f"{base_text}์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค." + return f"{base_text}์˜ {int(ratio)}๋ฐฐ์ž…๋‹ˆ๋‹ค." + + if ratio > 1.5: + # ๋ฐ˜์˜ฌ๋ฆผ ํ•œํ›„, ์˜ฌ๋ฆผ์ด๋ฉด ํฌ๋‹ค, ๋‚ด๋ฆผ์ด๋ฉด ์ž‘๋‹ค ํ‘œ์‹œ + rounded_ratio = round(ratio) + if rounded_ratio > ratio: # 2.0 > 1.9 + return f"{base_text}์˜ {rounded_ratio}๋ฐฐ๋ณด๋‹ค ์กฐ๊ธˆ ์ž‘์Šต๋‹ˆ๋‹ค." + if rounded_ratio < ratio: # 2.0 < 2.2 + return f"{base_text}์˜ {rounded_ratio}๋ฐฐ๋ณด๋‹ค ์กฐ๊ธˆ ํฝ๋‹ˆ๋‹ค." + if ratio > 1.0: + return f"{base_text}๋ณด๋‹ค ์กฐ๊ธˆ ํฝ๋‹ˆ๋‹ค." + if 0.5 <= ratio < 1.0: + return f"{base_text}๋ณด๋‹ค ์กฐ๊ธˆ ์ž‘์Šต๋‹ˆ๋‹ค." + return f"{base_text}๋ณด๋‹ค ๋ฐ˜ ์ด์ƒ ์ž‘์Šต๋‹ˆ๋‹ค." + + width_description = describe_ratio_first(width_ratio, compare_name, "๋„ˆ๋น„") + height_description = describe_ratio(height_ratio, compare_name, "๋†’์ด") + + description = ( + f"๋ฐฐ์†ก๋ฐ›๋Š” ์ œํ’ˆ์˜ ์‹ค์ œ ๋„ˆ๋น„๋Š” {int(product_actual_width)}cm ์ •๋„๋กœ {width_description}, ์‹ค์ œ ๋†’์ด๋Š” {int(product_actual_height)}cm ์ •๋„๋กœ {height_description}" + ) + + return description + + +def process_row(row, model): + detection_result = get_detection_from_image(row["ํฌ๊ธฐ ์ด๋ฏธ์ง€ URL"], model) + + if detection_result: + return process_result_with_actual_size_desc(detection_result) + return "์ด๋ฏธ์ง€ ๋ถ„์„ ์‹คํŒจ" + + + +if __name__ == "__main__": + model = YOLO("/data/ephemeral/home/workspace/personal/size_info/ultralytics/runs/detect/train14/weights/best.pt") + + df = pd.read_csv("250201_image_comparison.csv") + df["size_description"] = df.apply(lambda row: process_row(row, model), axis=1) + + df.to_csv("size_description_output.csv", index=False) diff --git a/models/size_description/src/train.py b/models/size_description/src/train.py new file mode 100644 index 0000000..08c809b --- /dev/null +++ b/models/size_description/src/train.py @@ -0,0 +1,21 @@ +import requests +from ultralytics import YOLO +from PIL import Image +from io import BytesIO + + +def download_image(url): + response = requests.get(url) + response.raise_for_status() + return Image.open(BytesIO(response.content)) + +def train_yolo(): + # YOLO ๋ชจ๋ธ ํ•™์Šต + model = YOLO("yolo11m.pt") + model.train(data="size_info.yaml", epochs=12) + + results = model.val() + success = model.export(format="onnx") + +if __name__ == "__main__": + train_yolo() \ No newline at end of file diff --git a/models/thumbnail_description/.DS_Store b/models/thumbnail_description/.DS_Store new file mode 100644 index 0000000..a605e32 Binary files /dev/null and b/models/thumbnail_description/.DS_Store differ diff --git a/models/thumbnail_description/.gitkeep b/models/thumbnail_description/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/thumbnail_description/README.md b/models/thumbnail_description/README.md new file mode 100644 index 0000000..4f5d443 --- /dev/null +++ b/models/thumbnail_description/README.md @@ -0,0 +1,157 @@ +# ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ์„ค๋ช… + +> ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ์„ค๋ช… ๊ธฐ๋Šฅ์€ ์‹œ๊ฐ์žฅ์• ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ์˜ ์™ธํ˜•๊ณผ ํฌ์žฅ ์ƒํƒœ๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค. +> ์ด ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ƒํ’ˆ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ํฌ์žฅ ์ƒํƒœ(์ƒ‰์ƒ, ์žฌ์งˆ, ํˆฌ๋ช…์„ฑ), ๊ตฌ์„ฑ, ๋””์ž์ธ ๋“ฑ์˜ ์‹œ๊ฐ์  ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. +> ์‹œ๊ฐ์žฅ์• ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ์˜ ์™ธํ˜•๊ณผ ํฌ์žฅ ์ƒํƒœ๋ฅผ ์ดํ•ดํ•˜์—ฌ ๋ณด๋‹ค ํŽธ๋ฆฌํ•œ ์˜จ๋ผ์ธ ์‡ผํ•‘ ๊ฒฝํ—˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. +> ์ž‘์„ฑ์ž : ์œค์„ ์›… + +--- + +## ๊ฐœ์š” + +์‹œ๊ฐ์žฅ์• ์ธ ์‚ฌ์šฉ์ž์—๊ฒŒ **์ƒํ’ˆ ์ด๋ฏธ์ง€**๋ฅผ ๊ฐ๊ด€์ ์ด๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ **์ด๋ฏธ์ง€ ์บก์…”๋‹** ์‹œ์Šคํ…œ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. + +1. **VLM ๋ชจ๋ธ Inference** + - Janus-Pro, Qwen2.5_VL ๋“ฑ์„ ํ†ตํ•ด ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +2. **ํ›„์ฒ˜๋ฆฌ (Post_processing)** + - HyperCLOVA HCX-003 ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜์—ฌ ๋ฒˆ์—ญ ๋ฐ Few-shot ๋ฐฉ์‹ ๋“ฑ์„ ํ†ตํ•ด ์„ค๋ช…์˜ ํ’ˆ์งˆ์„ ๋†’์ž…๋‹ˆ๋‹ค. +3. **ํŒŒ์ธํŠœ๋‹ (Finetuning)** + - GPT-4o ์ƒ์„ฑ๊ณผ ์ˆ˜๋™๊ฒ€์ˆ˜๋กœ ๊ตฌ์„ฑํ•œ ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ Janus-Pro๋ฅผ ํŒŒ์ธํŠœ๋‹ํ•˜์—ฌ ์ •๊ตํ•œ ์„ค๋ช… ์„ฑ๋Šฅ์— ๋„์ „ํ•ฉ๋‹ˆ๋‹ค. +4. **ํ‰๊ฐ€ (Evaluation)** + - OpenAI GPT-4o ๋ชจ๋ธ์„ ํ™œ์šฉํ•ด ์ ์ˆ˜๋ฅผ ๋งค๊ฒจ ์„ค๋ช…์˜ ํ’ˆ์งˆ์„ ์ธก์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +> `config.yaml`์—์„œ **API Key, ํŒŒ์ผ ๊ฒฝ๋กœ**, ์‹คํ–‰ ์—ฌ๋ถ€ ๋“ฑ์„ ๊ด€๋ฆฌํ•˜์—ฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ์œ ์—ฐํ•˜๊ฒŒ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. +--- +## ํŒŒ์ดํ”„๋ผ์ธ +แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2025-02-19 แ„‹แ…ฉแ„’แ…ฎ 12 05 04 + +## ์„ฑ๋Šฅ ๊ณ ๋„ํ™” ๊ณผ์ • +แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2025-02-19 แ„‹แ…ฉแ„’แ…ฎ 12 05 40 + + +--- + +## ํด๋” ๊ตฌ์กฐ + +```bash +thumbnail_description/ +โ”œโ”€โ”€ config +โ”‚ โ””โ”€โ”€ config.yaml # ์„ค์ • ํŒŒ์ผ(API Key, ๊ฒฝ๋กœ, ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€) +โ”œโ”€โ”€ data +โ”‚ โ”œโ”€โ”€ ... (๊ฐ์ข… CSV ๋ฐ์ดํ„ฐ) +โ”‚ โ””โ”€โ”€ ... +โ”œโ”€โ”€ hcx_prompt +โ”‚ โ”œโ”€โ”€ system_janus_pro_hcx_fewshot.txt +โ”‚ โ”œโ”€โ”€ system_janus_pro_hcx_translation.txt +โ”‚ โ”œโ”€โ”€ system_qwen2_5_pp_hcx.txt +โ”‚ โ”œโ”€โ”€ user_janus_pro_hcx_fewshot.txt +โ”‚ โ”œโ”€โ”€ user_janus_pro_hcx_translation.txt +โ”‚ โ””โ”€โ”€ user_qwen2_5_pp_hcx.txt +โ”œโ”€โ”€ prompt +โ”‚ โ”œโ”€โ”€ deepseek_prompt.txt +โ”‚ โ”œโ”€โ”€ janus_prompt.txt +โ”‚ โ”œโ”€โ”€ maal_prompt.txt +โ”‚ โ”œโ”€โ”€ qwen2_5_prompt.txt +โ”‚ โ”œโ”€โ”€ qwen2_prompt.txt +โ”‚ โ””โ”€โ”€ unsloth_prompt.txt +โ”‚ src +โ”‚ โ”œโ”€โ”€ description_pipeline # ์„ค๋ช… ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ +โ”‚ โ”‚ โ”œโ”€โ”€ inference_model # ๋ชจ๋ธ ์ถ”๋ก  ์ฝ”๋“œ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ deepseekvl.py # DeepSeek_VL์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ finetuned_janus_pro.py # ์ง์ ‘ ํŒŒ์ธํŠœ๋‹ํ•œ Janus Pro์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ janus_pro.py # Janus Pro์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ maal.py # MAAL์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ qwen2_5_vl.py # Qwen2.5_VL์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ qwen2_vl.py # Qwen2_VL์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ unsloth_qwen2_vl.py # Unsloth_Qwen2_VL์„ ํ™œ์šฉํ•œ ์ธ๋„ค์ผ ์„ค๋ช… ์ƒ์„ฑ +โ”‚ โ”‚ โ”œโ”€โ”€ post_processing # ํ›„์ฒ˜๋ฆฌ ๊ด€๋ จ ์ฝ”๋“œ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ janus_pro_hcx_translation.py # HCX ๋ฒˆ์—ญ์„ ํ™œ์šฉํ•œ Janus Pro ํ›„์ฒ˜๋ฆฌ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ janus_pro_papago_translation.py # Papago ๋ฒˆ์—ญ์„ ํ™œ์šฉํ•œ Janus Pro ํ›„์ฒ˜๋ฆฌ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ janus_pro_pp_hcx.py # Janus Pro ๋ชจ๋ธ์˜ PP-HCX ๊ธฐ๋ฐ˜ ํ›„์ฒ˜๋ฆฌ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ qwen2_5_pp_hcx.py # Qwen2.5 ๋ชจ๋ธ์˜ PP-HCX ๊ธฐ๋ฐ˜ ํ›„์ฒ˜๋ฆฌ +โ”‚ โ”‚ โ”œโ”€โ”€ evaluation # ํ‰๊ฐ€ ๊ด€๋ จ ์ฝ”๋“œ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ gpt_eval_323.py # GPT ๊ธฐ๋ฐ˜ ํ‰๊ฐ€์…‹ ์ธ๋„ค์ผ ์„ค๋ช… ํ‰๊ฐ€ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ gpt_eval.py # GPT ๊ธฐ๋ฐ˜ ์ „์ฒด ๋ฐ์ดํ„ฐ ์…‹ ์ธ๋„ค์ผ ์„ค๋ช… ํ‰๊ฐ€ +โ”œโ”€โ”€ sft_pipeline # SFT(์ง€๋„ ํ•™์Šต ๋ฏธ์„ธ ์กฐ์ •) ๊ด€๋ จ ์ฝ”๋“œ +โ”‚ โ”œโ”€โ”€ detailed_feature_description.py # 1327๊ฐœ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ GPT๊ธฐ๋ฐ˜ ์‹ค๋ฒ„๋ผ๋ฒจ ์ถ”์ถœ ์ฝ”๋“œ +โ”‚ โ””โ”€โ”€ janus_pro_7b_finetuning.py # ๊ณจ๋“œ๋ผ๋ฒจ(์‹ค๋ฒ„๋ผ๋ฒจ + ๊ฒ€์ˆ˜)ํ™œ์šฉ Janus Pro ํŒŒ์ธํŠœ๋‹ + +โ”œโ”€โ”€ utils +โ”‚ โ”œโ”€โ”€ __init__.py +โ”‚ โ””โ”€โ”€ common_utils.py # ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ์ •์˜ +โ””โ”€โ”€ main.py # ๋ฉ”์ธ ์‹คํ–‰ ํŒŒ์ผ +``` +--- + +## ์ž…๋ ฅ(Input)๊ณผ ์ถœ๋ ฅ(Output) + +### ์ž…๋ ฅ + +1. **์ƒํ’ˆ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ๋ฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ** + - **์ด๋ฏธ์ง€ ํŒŒ์ผ**: + ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€๊ฐ€ ์‹œ์Šคํ…œ์˜ ์ฃผ์š” ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. + - **CSV ๋ฐ์ดํ„ฐ**: + `data` ํด๋” ๋‚ด์˜ CSV ํŒŒ์ผ๋“ค์€ ๊ฐ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(์˜ˆ: ์ƒํ’ˆ ์ฝ”๋“œ, ์นดํ…Œ๊ณ ๋ฆฌ, ๊ธฐ์กด ์„ค๋ช… ๋“ฑ)๋ฅผ ํฌํ•จํ•˜๋ฉฐ, ์ด๋ฏธ์ง€์™€ ์—ฐ๊ณ„๋˜์–ด ํ›„์ฒ˜๋ฆฌ ๋ฐ ํ‰๊ฐ€ ๊ณผ์ •์—์„œ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค. + +2. **์„ค์ • ์ •๋ณด ๋ฐ API ์ธ์ฆ** + - **config.yaml**: + API Key, ํŒŒ์ผ ๊ฒฝ๋กœ, ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€ ๋“ฑ ์ „์ฒด ์‹œ์Šคํ…œ์˜ ์„ค์ • ์ •๋ณด๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. + - **๋ฒˆ์—ญ ๋ฐ ํ›„์ฒ˜๋ฆฌ ๊ด€๋ จ ์„ค์ •**: + HyperCLOVA HCX-003, OpenAI API Key ๋“ฑ ํ›„์ฒ˜๋ฆฌ์™€ ํ‰๊ฐ€์— ํ•„์š”ํ•œ ์ธ์ฆ ์ •๋ณด์™€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. + +3. **ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ** + - **hcx_prompt ํด๋”**: + Janus-Pro, Qwen2.5_VL ๋“ฑ ๋‹ค์–‘ํ•œ ๋ชจ๋ธ์˜ ๋ฒˆ์—ญ ๋ฐ Few-shot ํ•™์Šต์— ํ•„์š”ํ•œ ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + - **prompt ํด๋”**: + DeepSeek, Janus, MAAL, Qwen2_VL ๋“ฑ ๋‹ค์–‘ํ•œ VLM ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ธํผ๋Ÿฐ์Šค ์š”์ฒญ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. + +--- + +### ์ถœ๋ ฅ (Output) + +1. **์ธ๋„ค์ผ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ํ…์ŠคํŠธ ์„ค๋ช…** + - **๊ธฐ๋ณธ ์ƒ์„ฑ ๊ฒฐ๊ณผ**: + `src/description` ํด๋” ๋‚ด์˜ ๊ฐ ๋ชจ๋“ˆ(์˜ˆ: `janus_pro.py`, `qwen2_5_vl.py` ๋“ฑ)์€ ์ž…๋ ฅ๋œ ์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํฌ์žฅ ์ƒํƒœ(์ƒ‰์ƒ, ์žฌ์งˆ, ํˆฌ๋ช…์„ฑ), ๊ตฌ์„ฑ, ๋””์ž์ธ ๋“ฑ์˜ ์‹œ๊ฐ์  ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ํ…์ŠคํŠธ ์„ค๋ช…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. + - **ํ›„์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ**: + - `src/post_processing` ํด๋” ๋‚ด์˜ ์Šคํฌ๋ฆฝํŠธ๋“ค์€ ์ดˆ๊ธฐ ์ƒ์„ฑ๋œ ํ…์ŠคํŠธ ์„ค๋ช…์„ ๋ฒˆ์—ญ(Papago ๋˜๋Š” HCX ๊ธฐ๋ฐ˜)ํ•˜๊ฑฐ๋‚˜ Few-shot ๊ธฐ๋ฒ•์„ ํ™œ์šฉํ•ด ํ’ˆ์งˆ์„ ๋ณด์ •ํ•ฉ๋‹ˆ๋‹ค. + - ์˜ˆ๋ฅผ ๋“ค์–ด, `janus_pro_hcx_translation.py`์™€ `qwen2_5_pp_hcx.py` ๋ชจ๋“ˆ์€ ๊ฐ๊ฐ ํ•ด๋‹น ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์— ๋Œ€ํ•ด ํ›„์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +2. **ํ‰๊ฐ€ ๋ฐ ์ ์ˆ˜ ์ •๋ณด** + - **GPT ํ‰๊ฐ€ ๊ฒฐ๊ณผ**: + `src/evaluation` ํด๋”์˜ `gpt_eval.py` ๋ฐ `gpt_eval_323.py` ์Šคํฌ๋ฆฝํŠธ๋Š” GPT-4o ๋ชจ๋ธ ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ์ƒ์„ฑ๋œ ํ…์ŠคํŠธ ์„ค๋ช…์˜ ํ’ˆ์งˆ์„ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. + - **์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ํ‰๊ฐ€**: + ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋Š” ์ตœ์ข… ์ถœ๋ ฅ๋ฌผ์˜ ์‹ ๋ขฐ๋„์™€ ํ’ˆ์งˆ ๊ฐœ์„ ์— ํ™œ์šฉ๋˜๋ฉฐ, ํŒŒ์ธํŠœ๋‹(์˜ˆ: Janus-Pro Finetuning) ๋“ฑ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. + +3. **์ตœ์ข… ์‚ฌ์šฉ์ž ์ œ๊ณต ๊ฒฐ๊ณผ** + - **์‹œ๊ฐ์žฅ์• ์ธ ๋Œ€์ƒ ์„ค๋ช… ํ…์ŠคํŠธ**: + ์ตœ์ข… ์ถœ๋ ฅ์€ ์‹œ๊ฐ์žฅ์• ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ์˜ ์™ธํ˜•๊ณผ ํฌ์žฅ ์ƒํƒœ๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ๊ด€์ ์ธ ํ…์ŠคํŠธ ์„ค๋ช… ํ˜•ํƒœ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. + - **์ €์žฅ ๋ฐ ํ™œ์šฉ**: + ์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ์„ค์ •๋œ ํŒŒ์ผ ๊ฒฝ๋กœ์— ์ €์žฅ๋˜๋ฉฐ, ์ดํ›„ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค(์˜ˆ: ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ)์— ํ†ตํ•ฉ๋˜์–ด ์‹ค์ œ ์„œ๋น„์Šค์— ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค. + +--- +## ์„ค์น˜ ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ• +### 1) ํ™˜๊ฒฝ ๊ตฌ์ถ• +- Python 3.10.15 ๋ฒ„์ „ ๊ถŒ์žฅ +- ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜ +```bash +conda env create -f environment.yml +``` + +### 2) ์„ค์ • +- `config/config.yaml` ํŒŒ์ผ์—์„œ ๋‹ค์Œ ์ •๋ณด๋ฅผ ์ ์ ˆํžˆ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + - **API Key / Request ID**: HyperCLOVA X ์ธ์ฆ ์ •๋ณด + - **OpenAI API Key**: GPT ๋ชจ๋ธ ์‚ฌ์šฉ ์‹œ ํ•„์š” + - **ํŒŒ์ผ ๊ฒฝ๋กœ**: ๋ฐ์ดํ„ฐ ํŒŒ์ผ ์œ„์น˜, ํŒŒ์ธํŠœ๋‹ ๊ฒฐ๊ณผ ์ €์žฅ ๊ฒฝ๋กœ ๋“ฑ + - **ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์—ฌ๋ถ€**: `pipeline` ์„น์…˜์˜ `true`/`false` ๊ฐ’์œผ๋กœ ํฌ๋กค๋ง/์ธํผ๋Ÿฐ์Šค/ํŒŒ์ธํŠœ๋‹ ๋“ฑ ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์ œ์–ด + - **ํŒŒ์ธํŠœ๋‹ ์„ค์ •**: TBD + +### 3) ์‹คํ–‰ +- ๊ธฐ๋ณธ ์‹คํ–‰ (๊ธฐ๋ณธ `config/config.yaml` ์‚ฌ์šฉ ์‹œ) +```bash +python main.py +``` +- ๋ณ„๋„ ์„ค์ •ํŒŒ์ผ ์‚ฌ์šฉ +```bash +python main.py --config config/config_name.yaml +``` +--- diff --git a/models/thumbnail_description/config/config.yaml b/models/thumbnail_description/config/config.yaml new file mode 100644 index 0000000..7c6c5d3 --- /dev/null +++ b/models/thumbnail_description/config/config.yaml @@ -0,0 +1,46 @@ +hcx_api: + host: "https://clovastudio.stream.ntruss.com" + api_key: "YOUR_API_KEY" + request_id: "YOUR_REQUEST_ID" + +papago_api: + client_id: "YOUR_CLIENT_ID" + client_secret: "YOUR_CLIENT_SECRET" + +openai: + api_key: "OPENAI_API_KEY" + +paths: + data_dir: "./data" + prompt_dir: "./prompt" + + # ์‚ฌ์šฉ๋  CSV ํŒŒ์ผ ๊ฒฝ๋กœ๋“ค + cleaned_text_contents: "cleaned_text_contents.csv" + Foodly_323_product_information: "Foodly_323_product_information.csv" + thumbnail_1347_gpt_human_labeling_train: "thumbnail_1347_gpt_human_labeling_train.csv" + + +pipeline: + sft_pipeline: + detailed_feature_description: false + janus_pro_7b_finetuning: false + + description_pipeline: + inference_model: + deepseekvl: false + finetuned_janus_pro : false + janus_pro: true + maal: false + qwen2_vl: false + qwen2_5_vl: false + unsloth_qwen2_vl: false + + post_processing: + janus_pro_papago: false + janus_pro_hcx_translation: true + janus_pro_pp_hcx: true + qwen2_5_pp_hcx: false + + evaluation: + gpt_eval: false + gpt_eval_323: true \ No newline at end of file diff --git a/models/thumbnail_description/data/.gitkeep b/models/thumbnail_description/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/models/thumbnail_description/environment.yml b/models/thumbnail_description/environment.yml new file mode 100644 index 0000000..799d5e9 --- /dev/null +++ b/models/thumbnail_description/environment.yml @@ -0,0 +1,185 @@ +name: thumbnail +channels: + - xformers + - pytorch + - nvidia + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=1_gnu + - asttokens=3.0.0=pyhd8ed1ab_1 + - blas=1.0=mkl + - bzip2=1.0.8=h5eee18b_6 + - ca-certificates=2024.12.14=hbcca054_0 + - comm=0.2.2=pyhd8ed1ab_1 + - cuda-cudart=12.1.105=0 + - cuda-cupti=12.1.105=0 + - cuda-libraries=12.1.0=0 + - cuda-nvrtc=12.1.105=0 + - cuda-nvtx=12.1.105=0 + - cuda-opencl=12.4.127=0 + - cuda-runtime=12.1.0=0 + - cudatoolkit=11.7.0=hd8887f6_10 + - debugpy=1.8.11=py311h6a678d5_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - filelock=3.13.1=py311h06a4308_0 + - gmp=6.2.1=h295c915_3 + - gmpy2=2.1.2=py311hc9b5ff0_0 + - importlib-metadata=8.5.0=pyha770c72_1 + - intel-openmp=2023.1.0=hdb19cb5_46306 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.31.0=pyh707e725_0 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=py311h06a4308_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - ld_impl_linux-64=2.40=h12ee557_0 + - libcublas=12.1.0.26=0 + - libcufft=11.0.2.4=0 + - libcufile=1.9.1.3=0 + - libcurand=10.3.5.147=0 + - libcusolver=11.4.4.55=0 + - libcusparse=12.0.2.55=0 + - libffi=3.4.4=h6a678d5_1 + - libgcc-ng=11.2.0=h1234567_1 + - libgomp=11.2.0=h1234567_1 + - libnpp=12.0.2.50=0 + - libnvjitlink=12.1.105=0 + - libnvjpeg=12.1.1.14=0 + - libsodium=1.0.18=h36c2ea0_1 + - libstdcxx-ng=11.2.0=h1234567_1 + - libuuid=1.41.5=h5eee18b_0 + - llvm-openmp=14.0.6=h9e868ea_0 + - markupsafe=2.1.3=py311h5eee18b_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - mkl=2023.1.0=h213fc3f_46344 + - mpc=1.1.0=h10f8cd9_1 + - mpfr=4.0.2=hb69a4c5_1 + - mpmath=1.3.0=py311h06a4308_0 + - ncurses=6.4=h6a678d5_0 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.3=py311h06a4308_0 + - openssl=3.0.15=h5eee18b_0 + - packaging=24.2=pyhd8ed1ab_2 + - parso=0.8.4=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pip=24.2=py311h06a4308_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - prompt-toolkit=3.0.48=pyha770c72_1 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - python=3.11.11=he870216_0 + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - pytorch=2.5.1=py3.11_cuda12.1_cudnn9.1.0_0 + - pytorch-cuda=12.1=ha16c6d3_6 + - pytorch-mutex=1.0=cuda + - pyyaml=6.0.2=py311h5eee18b_0 + - pyzmq=26.2.0=py311h6a678d5_0 + - readline=8.2=h5eee18b_0 + - setuptools=75.1.0=py311h06a4308_0 + - six=1.17.0=pyhd8ed1ab_0 + - sqlite=3.45.3=h5eee18b_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - tbb=2021.8.0=hdb19cb5_0 + - tk=8.6.14=h39e8969_0 + - torchtriton=3.1.0=py311 + - tornado=6.4.2=py311h5eee18b_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=py311h06a4308_0 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.44.0=py311h06a4308_0 + - xformers=0.0.28.post3=py311_cu12.1.0_pyt2.5.1 + - xz=5.4.6=h5eee18b_1 + - yaml=0.2.5=h7b6447c_0 + - zeromq=4.3.5=h6a678d5_0 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.2.13=h5eee18b_1 + - pip: + - accelerate==1.2.1 + - aiohappyeyeballs==2.4.4 + - aiohttp==3.11.11 + - aiosignal==1.3.2 + - annotated-types==0.7.0 + - anyio==4.8.0 + - attrdict==2.0.1 + - attrs==24.3.0 + - av==14.0.1 + - bitsandbytes==0.45.0 + - certifi==2024.12.14 + - charset-normalizer==3.4.1 + - contourpy==1.3.1 + - cut-cross-entropy==24.12.3 + - cycler==0.12.1 + - datasets==3.2.0 + - decord==0.6.0 + - deepseek-vl==1.0.0 + - dill==0.3.8 + - distro==1.9.0 + - docstring-parser==0.16 + - einops==0.8.0 + - fonttools==4.55.6 + - frozenlist==1.5.0 + - fsspec==2024.9.0 + - h11==0.14.0 + - hf-transfer==0.1.8 + - httpcore==1.0.7 + - httpx==0.28.1 + - huggingface-hub==0.27.0 + - idna==3.10 + - janus==1.0.0 + - jiter==0.8.2 + - joblib==1.4.2 + - kiwisolver==1.4.8 + - levenshtein==0.26.1 + - markdown-it-py==3.0.0 + - matplotlib==3.10.0 + - mdurl==0.1.2 + - multidict==6.1.0 + - multiprocess==0.70.16 + - numpy==2.2.1 + - openai==1.61.1 + - pandas==2.2.3 + - peft==0.14.0 + - pillow==11.1.0 + - propcache==0.2.1 + - protobuf==3.20.3 + - psutil==6.1.1 + - pyarrow==18.1.0 + - pydantic==2.10.6 + - pydantic-core==2.27.2 + - pygments==2.19.0 + - pyparsing==3.2.1 + - python-levenshtein==0.26.1 + - pytz==2024.2 + - qwen-vl-utils==0.0.8 + - rapidfuzz==3.11.0 + - regex==2024.11.6 + - requests==2.32.3 + - rich==13.9.4 + - safetensors==0.5.0 + - scikit-learn==1.6.1 + - scipy==1.15.1 + - sentencepiece==0.2.0 + - shtab==1.7.1 + - sniffio==1.3.1 + - sympy==1.13.1 + - threadpoolctl==3.5.0 + - timm==1.0.14 + - tokenizers==0.21.0 + - torchvision==0.20.1 + - tqdm==4.67.1 + - transformers==4.49.0.dev0 + - trl==0.13.0 + - typeguard==4.4.1 + - tyro==0.9.5 + - tzdata==2024.2 + - unsloth==2025.1.6 + - unsloth-zoo==2025.1.5 + - urllib3==2.3.0 + - xxhash==3.5.0 + - yarl==1.18.3 +prefix: /data/ephemeral/home/.condaenv/envs/unsloth diff --git a/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_fewshot.txt b/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_fewshot.txt new file mode 100644 index 0000000..be4d58b --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_fewshot.txt @@ -0,0 +1,60 @@ +๋‹น์‹ ์€ ํ…์ŠคํŠธ๋ฅผ ์ •์ œํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๊ทœ์น™์„ ์—„๊ฒฉํžˆ ์ ์šฉํ•˜์—ฌ ์ž…๋ ฅ ํ…์ŠคํŠธ๋ฅผ ๋ณ€ํ™˜ํ•˜์„ธ์š”: + +1. ํ…์ŠคํŠธ ์ค‘ '๋†’์ด, ๋„ˆ๋น„, ๋ฌด๊ฒŒ' ๊ด€๋ จ ์ •๋ณด๋Š” ์™„์ „ํžˆ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. +2. ๋””์ž์ธ ์ž์ฒด์— ๋Œ€ํ•œ ํ‰๊ฐ€(์˜ˆ: ๋””์ž์ธ์ด ๋ฉ‹์ง€๋‹ค, ์•„๋ฆ„๋‹ต๋‹ค, ์„ธ๋ จ๋๋‹ค ๋“ฑ)๋Š” ๋ชจ๋‘ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + - ๋‹จ, ์ œํ’ˆ์˜ ์ฃผ์š” ์ŠคํŽ™(์žฌ์งˆ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ํˆฌ๋ช…์„ฑ ๋“ฑ)์€ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. +3. '์ถ”์ •' ํ˜น์€ '๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค' ๊ฐ™์€ ๋ถˆํ™•์‹คํ•œ ํ‘œํ˜„์ด๋‚˜ ์ถ”์ธก ๋ฌธ์žฅ์€ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. +4. ์ตœ์ข… ๊ฒฐ๊ณผ๋ฌผ์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + +์•„๋ž˜๋Š” ๊ทœ์น™์„ ์ ์šฉํ•œ ์˜ˆ์‹œ๋“ค์ž…๋‹ˆ๋‹ค. + +[์˜ˆ์‹œ 1] + +์ž…๋ ฅ: +์ œํ’ˆ์˜ ์ƒ‰์ƒ์€ ๋ถ„ํ™์ƒ‰์ด๊ณ , ๋””์ž์ธ์ด ๋งค์šฐ ์„ธ๋ จ๋˜์–ด ๋ณด์ธ๋‹ค. +๋†’์ด๋Š” ์•ฝ 30cm ์ •๋„๋กœ ์ถ”์ •๋œ๋‹ค. +๋ฌด๊ฒŒ๋Š” 200g ๋‚ด์™ธ์ผ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. +ํˆฌ๋ช…ํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด ์•ˆ์ชฝ ๋‚ด์šฉ๋ฌผ์ด ๋ณด์ž„. + +์ถœ๋ ฅ: +์ œํ’ˆ์˜ ์ƒ‰์ƒ์€ ๋ถ„ํ™์ƒ‰์ด๊ณ , ํˆฌ๋ช…ํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด ์•ˆ์ชฝ ๋‚ด์šฉ๋ฌผ์ด ๋ณด์ž„. + +(์„ค๋ช…: +- '๋””์ž์ธ์ด ๋งค์šฐ ์„ธ๋ จ๋˜์–ด ๋ณด์ธ๋‹ค' โ†’ ๋””์ž์ธ ํ‰๊ฐ€ ๋ฌธ์žฅ ์ œ๊ฑฐ +- '๋†’์ด๋Š” ์•ฝ 30cm ์ •๋„๋กœ ์ถ”์ •๋œ๋‹ค' โ†’ ๋†’์ด ์ •๋ณด ๋ฐ ์ถ”์ • ํ‘œํ˜„ ์ œ๊ฑฐ +- '๋ฌด๊ฒŒ๋Š” 200g ๋‚ด์™ธ์ผ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค' โ†’ ๋ฌด๊ฒŒ ์ •๋ณด ๋ฐ ์ถ”์ • ํ‘œํ˜„ ์ œ๊ฑฐ +) + +[์˜ˆ์‹œ 2] + +์ž…๋ ฅ: +ํฌ์žฅ์ง€ ํ˜•ํƒœ๋Š” ์ง์‚ฌ๊ฐํ˜•์ด๋ฉฐ, ๋ชจ๋˜ํ•œ ๋””์ž์ธ ๋•๋ถ„์— ์‹œ๊ฐ์ ์œผ๋กœ ๊น”๋”ํ•˜๋‹ค. +๋„ˆ๋น„๊ฐ€ ๋Œ€๋žต 20cm๋กœ ์˜ˆ์ƒ๋œ๋‹ค. +์ƒ‰์ƒ์€ ์ „์ฒด์ ์œผ๋กœ ์ง™์€ ํŒŒ๋ž€์ƒ‰์ด๊ณ , ์žฌ์งˆ์€ ํ”Œ๋ผ์Šคํ‹ฑ์ธ ๊ฒƒ์œผ๋กœ ์ถ”์ •๋œ๋‹ค. + +์ถœ๋ ฅ: +ํฌ์žฅ์ง€ ํ˜•ํƒœ๋Š” ์ง์‚ฌ๊ฐํ˜•์ด๋ฉฐ, ์ƒ‰์ƒ์€ ์ „์ฒด์ ์œผ๋กœ ์ง™์€ ํŒŒ๋ž€์ƒ‰์ด๊ณ , ์žฌ์งˆ์€ ํ”Œ๋ผ์Šคํ‹ฑ์ด๋‹ค. + +(์„ค๋ช…: +- '๋ชจ๋˜ํ•œ ๋””์ž์ธ ๋•๋ถ„์— ์‹œ๊ฐ์ ์œผ๋กœ ๊น”๋”ํ•˜๋‹ค' โ†’ ๋””์ž์ธ ํ‰๊ฐ€ ๋ฌธ์žฅ ์ œ๊ฑฐ +- '๋„ˆ๋น„๊ฐ€ ๋Œ€๋žต 20cm๋กœ ์˜ˆ์ƒ๋œ๋‹ค' โ†’ ๋„ˆ๋น„ ์ •๋ณด ๋ฐ ์ถ”์ • ํ‘œํ˜„ ์ œ๊ฑฐ +- '์žฌ์งˆ์€ ํ”Œ๋ผ์Šคํ‹ฑ์ธ ๊ฒƒ์œผ๋กœ ์ถ”์ •๋œ๋‹ค' โ†’ '์ถ”์ •' ์ œ๊ฑฐ ํ›„ '์žฌ์งˆ์€ ํ”Œ๋ผ์Šคํ‹ฑ์ด๋‹ค'๋กœ ๋ณ€๊ฒฝ +) + +[์˜ˆ์‹œ 3] + +์ž…๋ ฅ: +์ด ์ œํ’ˆ์€ ํˆฌ๋ช… ์šฉ๊ธฐ์— ๋“ค์–ด ์žˆ์–ด ์•ˆ์ด ํ›คํžˆ ๋ณด์ด๋ฉฐ, +์–ด๋‘์šด ์ดˆ์ฝœ๋ฆฟ์ƒ‰๊ณผ ์€์€ํ•œ ๊ธˆ์ƒ‰ ๋กœ๊ณ ๊ฐ€ ์ธ์ƒ์ ์ด๋‹ค. +๋ฌด๊ฒŒ๋Š” 350g ์ •๋„์ผ ๊ฒƒ ๊ฐ™๊ณ , +์ „์ฒด์ ์ธ ๋””์ž์ธ ์™„์„ฑ๋„๊ฐ€ ๋›ฐ์–ด๋‚˜ ๋ณด์ธ๋‹ค. + +์ถœ๋ ฅ: +์ด ์ œํ’ˆ์€ ํˆฌ๋ช… ์šฉ๊ธฐ์— ๋“ค์–ด ์žˆ์–ด ์•ˆ์ด ํ›คํžˆ ๋ณด์ด๋ฉฐ, ์–ด๋‘์šด ์ดˆ์ฝœ๋ฆฟ์ƒ‰๊ณผ ์€์€ํ•œ ๊ธˆ์ƒ‰ ๋กœ๊ณ ๊ฐ€ ์žˆ๋‹ค. + +(์„ค๋ช…: +- '๋ฌด๊ฒŒ๋Š” 350g ์ •๋„์ผ ๊ฒƒ ๊ฐ™๊ณ ' โ†’ ๋ฌด๊ฒŒ ์ •๋ณด ๋ฐ ์ถ”์ • ํ‘œํ˜„ ์ œ๊ฑฐ +- '์ „์ฒด์ ์ธ ๋””์ž์ธ ์™„์„ฑ๋„๊ฐ€ ๋›ฐ์–ด๋‚˜ ๋ณด์ธ๋‹ค' โ†’ ๋””์ž์ธ ํ‰๊ฐ€ ๋ฌธ์žฅ ์ œ๊ฑฐ +) + +์ด์ œ ๊ทœ์น™๊ณผ ์˜ˆ์‹œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์ž…๋ ฅ ํ…์ŠคํŠธ๋ฅผ ์ •์ œํ•˜์„ธ์š”. \ No newline at end of file diff --git a/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_translation.txt b/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_translation.txt new file mode 100644 index 0000000..64a7220 --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/system_janus_pro_hcx_translation.txt @@ -0,0 +1 @@ +๋‹น์‹ ์€ ์‹ํ’ˆ์˜ ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ์ „๋ฌธ ์นดํ”ผ๋ผ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๋ชฉํ‘œ๋Š” ์ƒํ’ˆ์˜ ๊ฐ€์น˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์†Œ๋น„์ž์˜ ๊ตฌ๋งค ๊ฒฐ์ •์„ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/models/thumbnail_description/hcx_prompt/system_qwen2_5_pp_hcx.txt b/models/thumbnail_description/hcx_prompt/system_qwen2_5_pp_hcx.txt new file mode 100644 index 0000000..a97844a --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/system_qwen2_5_pp_hcx.txt @@ -0,0 +1,2 @@ +๋‹น์‹ ์€ ์‹ํ’ˆ์„ ํ•ต์‹ฌ์ ์œผ๋กœ ์†Œ๊ฐœํ•˜๋Š” ์ œํ’ˆ ๋‹ด๋‹น๊ด€์ž…๋‹ˆ๋‹ค. +๋‹น์‹ ์˜ ๋ชฉํ‘œ๋Š” ์ตœ์†Œํ•œ์˜ ๋ฌธ๊ตฌ๋กœ ํŠน์ง•์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์†Œ๋น„์ž์˜ ๊ตฌ๋งค ๊ฒฐ์ •์„ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_fewshot.txt b/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_fewshot.txt new file mode 100644 index 0000000..d29268e --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_fewshot.txt @@ -0,0 +1 @@ +์ฃผ์–ด์ง„ '{model_output_text}'์—์„œ ๋†’์ด์™€ ๋„ˆ๋น„ ๋ฐ ๋ฌด๊ฒŒ ์ •๋ณด๋Š” ์ œ์™ธํ•˜์—ฌ ํ•œ๊ตญ์–ด๋กœ ํ•ด์„ํ•˜์„ธ์š”. ์ถ”์ •์˜ ๋งํˆฌ๋‚˜ '๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค'์™€ ๊ฐ™์€ ํ‘œํ˜„๋“ค์ด ๋“ค์–ด๊ฐ„ ๋ฌธ์žฅ์€ ์ œ๊ฑฐํ•˜์„ธ์š” ๋””์ž์ธ์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ํ‰๊ฐ€๋Š” ๋ชจ๋‘ ์ œ๊ฑฐํ•˜์„ธ์š”. ์ค‘๋ณต๋œ ํ‘œํ˜„๋“ค์„ ์ตœ๋Œ€ํ•œ ์ œ๊ฑฐํ•˜์„ธ์š”. \ No newline at end of file diff --git a/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_translation.txt b/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_translation.txt new file mode 100644 index 0000000..ebdf5c2 --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/user_janus_pro_hcx_translation.txt @@ -0,0 +1 @@ +์ฃผ์–ด์ง„ '{model_output_text}'์—์„œ ๋†’์ด์™€ ๋„ˆ๋น„ ๋ฐ ๋ฌด๊ฒŒ ์ •๋ณด๋Š” ์ œ์™ธํ•˜์—ฌ ํ•œ๊ตญ์–ด๋กœ ํ•ด์„ํ•˜์„ธ์š”. ์ถ”์ •์˜ ๋งํˆฌ๋‚˜ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค์™€ ๊ฐ™์€ ํ‘œํ˜„๋“ค์ด ๋“ค์–ด๊ฐ„ ๋ฌธ์žฅ์€ ์ œ๊ฑฐํ•˜๊ณ  ๋””์ž์ธ์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ํ‰๊ฐ€๋Š” ๋ชจ๋‘ ์ œ๊ฑฐํ•ด์ค˜ \ No newline at end of file diff --git a/models/thumbnail_description/hcx_prompt/user_qwen2_5_pp_hcx.txt b/models/thumbnail_description/hcx_prompt/user_qwen2_5_pp_hcx.txt new file mode 100644 index 0000000..86630a5 --- /dev/null +++ b/models/thumbnail_description/hcx_prompt/user_qwen2_5_pp_hcx.txt @@ -0,0 +1,6 @@ +{ + '{model_output_text}'์˜ ๋‘ ๋ฒˆ์งธ ๋ฌธ์žฅ ์ดํ›„ ๋ฌธ์žฅ๋“ค์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ๋งŒ ์ถœ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + ๊ตฌ์„ฑํ’ˆ, ์ธ์ฆ๋งˆํฌ๋ฅผ ์ž˜ ์š”์•ฝํ•ด์„œ ํ•œ ์ค„๋กœ ๋‚˜ํƒ€๋‚ด๊ณ  ์กฐ๋ฆฌ๋ฐฉ๋ฒ•๊ณผ ํ™œ์šฉ๋ฒ•์€ ์ ˆ๋Œ€ ์–ธ๊ธ‰ํ•˜์ง€ ๋งˆ์„ธ์š”. + ์ œํ’ˆ๋ช…์„ ๋งˆ์ง€๋ง‰์— ์–ธ๊ธ‰ํ•˜๊ณ  ํ•ด์š”์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฌธ์žฅ ๋งˆ๋ฌด๋ฆฌ ์„œ์ˆ ์–ด๋ฅผ '์ž…๋‹ˆ๋‹ค'๋กœ ์™„๋ฒฝํ•˜๊ฒŒ ๋งˆ๋ฌด๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + ๋„์–ด์“ฐ๊ธฐ์™€ ๋งž์ถค๋ฒ•์„ ํ‹€๋ฆฌ์ง€ ๋งˆ์„ธ์š”. +} \ No newline at end of file diff --git a/models/thumbnail_description/main.py b/models/thumbnail_description/main.py new file mode 100644 index 0000000..6c8626c --- /dev/null +++ b/models/thumbnail_description/main.py @@ -0,0 +1,124 @@ +import argparse +import yaml +import logging + +# SFT ํŒŒ์ดํ”„๋ผ์ธ ๋ชจ๋“ˆ import +from src.sft_pipeline import ( + detailed_feature_description, + janus_pro_7b_finetuning +) + +# Description ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด ๋ชจ๋ธ ์ถ”๋ก  ๋ชจ๋“ˆ import +from src.description_pipeline.inference_model import ( + deepseekvl, + janus_pro, + maal, + qwen2_vl, + qwen2_5_vl, + unsloth_qwen2_vl, + finetuned_janus_pro +) +# Description ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด ํ›„์ฒ˜๋ฆฌ ๋ชจ๋“ˆ import +from src.description_pipeline.post_processing import ( + janus_pro_papago_translation, + janus_pro_hcx_translation, + janus_pro_pp_hcx, + qwen2_5_pp_hcx +) +# Description ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด ํ‰๊ฐ€ ๋ชจ๋“ˆ import +from src.description_pipeline.evaluation import ( + gpt_eval, + gpt_eval_323 +) + +def setup_logger(): + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + +def run_sft_pipeline(config): + logging.info("SFT ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘") + # config.yaml์—์„œ sft ํŒŒ์ดํ”„๋ผ์ธ ๊ด€๋ จ ์„ค์ •์€ pipeline > sft_pipeline ์— ์œ„์น˜ํ•จ + sft_config = config.get("pipeline", {}).get("sft_pipeline", {}) + if sft_config.get("detailed_feature_description", False): + detailed_feature_description.run_detailed_feature_description(config) + if sft_config.get("janus_pro_7b_finetuning", False): + janus_pro_7b_finetuning.run_janus_pro_7b_finetuning(config) + logging.info("SFT ํŒŒ์ดํ”„๋ผ์ธ ์™„๋ฃŒ.") + +def run_description_pipeline(config): + logging.info("Description ํŒŒ์ดํ”„๋ผ์ธ ์‹œ์ž‘") + # config.yaml์—์„œ description ๊ด€๋ จ ์„ค์ •์€ pipeline > description_pipeline ์— ์œ„์น˜ํ•จ + desc_config = config.get("pipeline", {}).get("description_pipeline", {}) + + # 1) ๋ชจ๋ธ๋ณ„ Inference ๋‹จ๊ณ„ + inference_cfg = desc_config.get("inference_model", {}) + if inference_cfg.get("deepseekvl", False): + deepseekvl.run_inference(config) + if inference_cfg.get("janus_pro", False): + janus_pro.run_inference(config) + if inference_cfg.get("maal", False): + maal.run_inference(config) + if inference_cfg.get("qwen2_vl", False): + qwen2_vl.run_inference(config) + if inference_cfg.get("qwen2_5_vl", False): + qwen2_5_vl.run_inference(config) + if inference_cfg.get("unsloth_qwen2_vl", False): + unsloth_qwen2_vl.run_inference(config) + if inference_cfg.get("finetuned_janus_pro", False): + finetuned_janus_pro.run_inference(config) + + # 2) ํ›„์ฒ˜๋ฆฌ ๋‹จ๊ณ„ + postproc_cfg = desc_config.get("post_processing", {}) + if postproc_cfg.get("janus_pro_papago_translation", False): + janus_pro_papago_translation.run_post_processing(config) + if postproc_cfg.get("janus_pro_hcx_translation", False): + janus_pro_hcx_translation.run_post_processing(config) + if postproc_cfg.get("janus_pro_pp_hcx", False): + janus_pro_pp_hcx.run_post_processing(config) + if postproc_cfg.get("qwen2_5_pp_hcx", False): + qwen2_5_pp_hcx.run_post_processing(config) + + # 3) Evaluation ๋‹จ๊ณ„ + eval_cfg = desc_config.get("evaluation", {}) + if eval_cfg.get("gpt_eval", False): + gpt_eval.run_evaluation(config) + if eval_cfg.get("gpt_eval_323", False): + gpt_eval_323.run_evaluation(config) + + logging.info("Description ํŒŒ์ดํ”„๋ผ์ธ ์™„๋ฃŒ.") + +def main(): + setup_logger() + parser = argparse.ArgumentParser(description="ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ (๊ธฐ๋ณธ๊ฐ’: config/config.yaml)" + ) + parser.add_argument( + "--pipeline", + "-p", + choices=["sft", "description", "all"], + default="all", + help="์‹คํ–‰ํ•  ํŒŒ์ดํ”„๋ผ์ธ ์„ ํƒ (sft, description, all)" + ) + args = parser.parse_args() + + # ์„ค์ • ํŒŒ์ผ ๋กœ๋“œ + with open(args.config, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # ์„ ํƒํ•œ ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ + if args.pipeline in ["sft", "all"]: + run_sft_pipeline(config) + + if args.pipeline in ["description", "all"]: + run_description_pipeline(config) + + logging.info("All pipeline tasks completed.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/prompt/deepseek_prompt.txt b/models/thumbnail_description/prompt/deepseek_prompt.txt new file mode 100644 index 0000000..cb4aa6d --- /dev/null +++ b/models/thumbnail_description/prompt/deepseek_prompt.txt @@ -0,0 +1,4 @@ +Provide a detailed description of the packaging container (shape, material, design, color, and contents) +that ensures the caption is of high quality and accessible for visually impaired individuals. +Do not mention screen readers in the description under any circumstances. +Write an image evaluation based solely on facts. Do not mention any opinions or evaluations about the design. \ No newline at end of file diff --git a/models/thumbnail_description/prompt/janus_prompt.txt b/models/thumbnail_description/prompt/janus_prompt.txt new file mode 100644 index 0000000..97e26a3 --- /dev/null +++ b/models/thumbnail_description/prompt/janus_prompt.txt @@ -0,0 +1,15 @@ +You are a professional copywriter specializing in describing the appearance of food products. +Your goal is to help visually impaired individuals objectively understand the productโ€™s appearance, +enabling them to make informed purchasing decisions. + +Provide a detailed description of the packaging container (shape, material, color) that ensures +the caption is of high quality. If both the product design and the product are present, describe +only the product design. Do not describe any text data on the design or labels. + +"output_requirements": [ + "1. Output must be only 2 sentences.", + "2. The first sentence must describe the shape and material of the packaging container.", + "3. The second sentence must describe the color design and key features factually and concisely.", + "4. Do not mention screen readers or opinions in the description.", + "5. Reflect only text written in English and do not translate to Chinese." +] \ No newline at end of file diff --git a/models/thumbnail_description/prompt/maal_prompt.txt b/models/thumbnail_description/prompt/maal_prompt.txt new file mode 100644 index 0000000..c16efc6 --- /dev/null +++ b/models/thumbnail_description/prompt/maal_prompt.txt @@ -0,0 +1,14 @@ +{product_name}์ œํ’ˆ์˜ ํŠน์ง•(ํฌ์žฅ ์šฉ๊ธฐ ๋ชจ์–‘, ์žฌ์งˆ, ๋””์ž์ธ, ์ƒ‰, ๋‚ด์šฉ๋ฌผ ๋“ฑ)์— ๋Œ€ํ•ด +์ตœ๋Œ€ 70์ž ์ด๋‚ด๋กœ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”. +์‹œ๊ฐ์žฅ์• ์ธ์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ’ˆ์งˆ ๋†’์€ ์บก์…˜ ํ˜•์‹์„ ์œ ์ง€ํ•˜์„ธ์š”. +์ฒซ์ค„์—๋Š” '{product_name}์— ๋Œ€ํ•œ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค'๋ผ๊ณ  ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +0. ํฌ์žฅ์˜ ์™ธ๋ถ€ ๋””์ž์ธ๊ณผ ๋‚ด๋ถ€ ๋‚ด์šฉ๋ฌผ์„ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•˜์„ธ์š”. +1. ํฌ์žฅ์˜ ๋ชจ์–‘์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•˜์„ธ์š” (์˜ˆ: ์ง์‚ฌ๊ฐํ˜• ํ”Œ๋ผ์Šคํ‹ฑ ์šฉ๊ธฐ, ์›ํ˜• ์œ ๋ฆฌ๋ณ‘ ๋“ฑ). +2. ํฌ์žฅ ์žฌ์งˆ์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š” (์˜ˆ: ํˆฌ๋ช… ํ”Œ๋ผ์Šคํ‹ฑ, ์ข…์ด, ๋น„๋‹ ํŒฉ ๋“ฑ). +3. ์ƒ‰์ƒ์ด๋‚˜ ํˆฌ๋ช…๋„ ์ •๋ณด๊ฐ€ ๊ณ ๊ฐ ์ธ์‹์— ์œ ์šฉํ•˜๋„๋ก ์ž‘์„ฑํ•˜์„ธ์š”. +4. ๋‚ด์šฉ๋ฌผ์ด ์–ด๋–ป๊ฒŒ ์ €์žฅ๋˜๋Š”์ง€ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜์„ธ์š” (์˜ˆ: ์ง„๊ณต ํฌ์žฅ, ๊ฐœ๋ณ„ ํฌ์žฅ). +5. ์‹ค์ œ ์ƒํ’ˆ๊ณผ ์ผ์น˜ํ•˜๋„๋ก ๋‚ด์šฉ๋ฌผ ์ƒํƒœ๋ฅผ ๋ฌ˜์‚ฌํ•˜์„ธ์š” (์˜ˆ: ์•ก์ฒด ๋‚ด์šฉ๋ฌผ, ๋ฐ€๋ด‰ ์ฒ˜๋ฆฌ). +6. ํฌ์žฅ์˜ ์ฃผ์š” ์ƒ‰์ƒ๊ณผ ํˆฌ๋ช… ์—ฌ๋ถ€๋ฅผ ๋ช…ํ™•ํžˆ ์–ธ๊ธ‰ํ•˜์„ธ์š”. + +โ€ป 70์ž๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜, ์ตœ๋Œ€ํ•œ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ถ•์•ฝ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. \ No newline at end of file diff --git a/models/thumbnail_description/prompt/qwen2_5_prompt.txt b/models/thumbnail_description/prompt/qwen2_5_prompt.txt new file mode 100644 index 0000000..004d7a8 --- /dev/null +++ b/models/thumbnail_description/prompt/qwen2_5_prompt.txt @@ -0,0 +1,34 @@ +{ + "task": "์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์ด๋ฏธ์ง€ ์บก์…˜ ์ƒ์„ฑ (Qwen2.5)", + "input": { + "image": "์ด ์ด๋ฏธ์ง€๋Š” ์‹ํ’ˆ ํŒจํ‚ค์ง€๋กœ ๊ตฌ์„ฑ๋œ ์žฅ๋ฉด์ž…๋‹ˆ๋‹ค.", + "product_name": "{product_name}" + }, + "steps": [ + { + "step": 1, + "instruction": "ํฌ์žฅ ์šฉ๊ธฐ, ๋‚ด์šฉ๋ฌผ, ์ƒ‰์ƒ, ์žฌ์งˆ, ํˆฌ๋ช…๋„, ๋ฐ€๋ด‰ ์ƒํƒœ ๋“ฑ์„ ์„ค๋ช…ํ•˜์„ธ์š”.", + "actions": [ + "1. {product_name}์™€ ์—ฐ๊ด€๋œ ํ•ต์‹ฌ ๋ฌธ๊ตฌ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.", + "2. ํฌ์žฅ ์šฉ๊ธฐ์˜ ๊ตฌ์ฒด์  ํ˜•์ƒ์„ ์–ธ๊ธ‰ํ•˜์„ธ์š” (์˜ˆ: ์›ํ˜•, ์ง์‚ฌ๊ฐํ˜•, ์œ ๋ฆฌ๋ณ‘ ๋“ฑ).", + "3. ํฌ์žฅ ์žฌ์งˆ(ํ”Œ๋ผ์Šคํ‹ฑ, ์ข…์ด, ์œ ๋ฆฌ ๋“ฑ)๊ณผ ํˆฌ๋ช… ์—ฌ๋ถ€(ํˆฌ๋ช…, ๋ถˆํˆฌ๋ช…)๋ฅผ ๋ช…ํ™•ํžˆ ์ ์œผ์„ธ์š”.", + "4. ๋‚ด์šฉ๋ฌผ์˜ ํ˜•ํƒœ(๋ฉ์–ด๋ฆฌ, ์•ก์ฒด, ๊ฐ€๋ฃจ ๋“ฑ)์™€ ํฌ์žฅ ์ƒํƒœ(๊ฐœ๋ณ„, ์ง„๊ณต ๋“ฑ)๋ฅผ ๊ธฐ์ˆ ํ•˜์„ธ์š”." + ] + }, + { + "step": 2, + "instruction": "์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์ ‘๊ทผ์„ฑ ์„ค๋ช…์„ ์ž‘์„ฑํ•˜์„ธ์š”.", + "actions": [ + "1. ์ฒซ ๋ฌธ์žฅ์€ '{product_name}์˜ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค'๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”.", + "2. 80์ž ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•ต์‹ฌ ํฌ์ธํŠธ๋งŒ ์ „๋‹ฌํ•˜์„ธ์š”.", + "3. ์ค‘๋ณต ํ‘œํ˜„ ์—†์ด ์ง๊ด€์ ์ธ ๋ฌธ์žฅ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.", + "4. ๋ถˆํ•„์š”ํ•œ ์ˆ˜์‹์–ด๋Š” ์ตœ๋Œ€ํ•œ ๋ฐฐ์ œํ•˜๊ณ  ์ง์„ค์ ์œผ๋กœ ๋ฌ˜์‚ฌํ•˜์„ธ์š”." + ] + } + ], + "output_requirements": [ + "1. ์ถœ๋ ฅ์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.", + "2. 80์ž ์ด๋‚ด๋กœ ์š”์•ฝํ•ด์ฃผ์„ธ์š”.", + "3. ์‹ค์ œ ์ƒํ’ˆ ์ •๋ณด๋ฅผ ํฌ๊ฒŒ ๋ฒ—์–ด๋‚˜์ง€ ๋งˆ์„ธ์š”." + ] +} \ No newline at end of file diff --git a/models/thumbnail_description/prompt/qwen2_prompt.txt b/models/thumbnail_description/prompt/qwen2_prompt.txt new file mode 100644 index 0000000..7d195e9 --- /dev/null +++ b/models/thumbnail_description/prompt/qwen2_prompt.txt @@ -0,0 +1,37 @@ +{ + "task": "์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์ด๋ฏธ์ง€ ์บก์…˜ ์ƒ์„ฑ", + "input": { + "image": "ํ•ด๋‹น ์ด๋ฏธ์ง€๋Š” ์‹๋ฃŒํ’ˆ ํฌ์žฅ๊ณผ ๋‚ด์šฉ์„ ์„ค๋ช…ํ•˜๋Š” ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค.", + "product_name": "{product_name}" + }, + "steps": [ + { + "step": 1, + "instruction": "์ œํ’ˆ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ํŠน์ง•์„ ์ค‘์‹ฌ์œผ๋กœ, ๋‚ด์šฉ๋ฌผ๊ณผ ํฌ์žฅ ์ƒํƒœ, ๋””์ž์ธ, ์žฌ์งˆ์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜์„ธ์š”.", + "actions": [ + "1. {product_name}๊ณผ ๊ด€๋ จ๋œ ํ•ต์‹ฌ ๋ฌธ๊ตฌ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.", + "2. ๋‚ด์šฉ๋ฌผ์˜ ํ˜•ํƒœ์™€ ํฌ์žฅ ์ƒํƒœ๋ฅผ ์ •๋ฆฌํ•˜์„ธ์š”.", + "3. ์ฃผ์š” ์ƒ‰์ƒ๊ณผ ๋””์ž์ธ ์š”์†Œ๋ฅผ ๊ธฐ์ˆ ํ•˜์„ธ์š”.", + "4. ํฌ์žฅ์˜ ์žฌ์งˆ๊ณผ ํ˜•ํƒœ๋ฅผ ๊ฐ๊ด€์ ์œผ๋กœ ํ‘œํ˜„ํ•˜์„ธ์š”.", + "5. ํฌ์žฅ์ด ํˆฌ๋ช…ํ•œ์ง€, ๋ฐ€๋ด‰ ์—ฌ๋ถ€๊ฐ€ ์–ด๋– ํ•œ์ง€ ์ ์–ด์ฃผ์„ธ์š”." + ] + }, + { + "step": 2, + "instruction": "์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์ ‘๊ทผ์„ฑ ์„ค๋ช…์„ ์ž‘์„ฑํ•˜์„ธ์š”.", + "actions": [ + "1. ์ฒซ ๋ฌธ์žฅ์€ '{product_name}์˜ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค'๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”.", + "2. 80์ž ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”.", + "3. ์ค‘๋ณต ํ‘œํ˜„ ์—†์ด ์ง๊ด€์ ์ธ ๋ฌธ์žฅ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.", + "4. ๋ถˆํ•„์š”ํ•œ ๋‹จ์–ด๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ •ํ™•์„ฑ์„ ์œ ์ง€ํ•˜์„ธ์š”." + ] + } + ], + "output_requirements": [ + "1. ์ถœ๋ ฅ์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.", + "2. ์ฒซ ๋ฌธ์žฅ์„ '{product_name}์˜ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค'๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + "3. ์ตœ๋Œ€ 80์ž๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ํ•ต์‹ฌ ์ •๋ณด๋งŒ ๋‹ด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + "4. ์ค‘๋ณต๋œ ํ‘œํ˜„ ์—†์ด ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์„ธ์š”.", + "5. ์‹ค์ œ ์ด๋ฏธ์ง€์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์ •๋ณด๋Š” ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”." + ] +} \ No newline at end of file diff --git a/models/thumbnail_description/prompt/unsloth_prompt.txt b/models/thumbnail_description/prompt/unsloth_prompt.txt new file mode 100644 index 0000000..ef0f8da --- /dev/null +++ b/models/thumbnail_description/prompt/unsloth_prompt.txt @@ -0,0 +1,35 @@ +{ + "task": "์ธ๋„ค์ผ ์ด๋ฏธ์ง€ ๋ฌ˜์‚ฌ", + "input": { + "image": "{product_name}์˜ ์ž…๋ ฅ ์ด๋ฏธ์ง€๋Š” ๋Œ€ํ‘œ์„ฑ์„ ๋ ๋Š” ์‹๋ฃŒํ’ˆ์˜ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค.", + "product_name": "{product_name}" + }, + "steps": [ + { + "step": 1, + "instruction": "ํฌ์žฅ ์šฉ๊ธฐ, ๋‚ด์šฉ๋ฌผ, ๋””์ž์ธ ์š”์†Œ๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜์„ธ์š”.", + "actions": [ + "0. ์™ธ๋ถ€ ๋””์ž์ธ๊ณผ ๋‚ด๋ถ€ ๋‚ด์šฉ๋ฌผ์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ž‘์„ฑํ•˜์„ธ์š”.", + "1. ํฌ์žฅ์˜ ๋ชจ์–‘(์ง์‚ฌ๊ฐํ˜•, ์›ํ˜•, ์ข…์ด ์ƒ์ž, ํ”Œ๋ผ์Šคํ‹ฑ ์šฉ๊ธฐ ๋“ฑ)์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•˜์„ธ์š”.", + "2. ํฌ์žฅ ์žฌ์งˆ(์ข…์ด, ์œ ๋ฆฌ, ๊ธˆ์†, ๋น„๋‹ ๋“ฑ)์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์–ธ๊ธ‰ํ•˜์„ธ์š”.", + "3. ์ƒ‰์ƒ์ด๋‚˜ ํˆฌ๋ช…๋„ ์ •๋ณด๋ฅผ ๋ถ„๋ช…ํžˆ ๊ธฐ์žฌํ•˜์„ธ์š” (ํˆฌ๋ช… ํ”Œ๋ผ์Šคํ‹ฑ, ๋ถˆํˆฌ๋ช… ์ข…์ด ๋“ฑ).", + "4. ๋‚ด์šฉ๋ฌผ์ด ์–ด๋–ป๊ฒŒ ์ €์žฅ๋๋Š”์ง€ (๊ฐœ๋ณ„ํฌ์žฅ, ์ง„๊ณตํฌ์žฅ ๋“ฑ)๋ฅผ ๊ฐ„๋‹จํžˆ ์ ์œผ์„ธ์š”." + ] + }, + { + "step": 2, + "instruction": "์‹œ๊ฐ์žฅ์• ์ธ์„ ์œ„ํ•œ ์ ‘๊ทผ์„ฑ ์„ค๋ช…์„ ์ž‘์„ฑํ•˜์„ธ์š”.", + "actions": [ + "1. ์ฒซ์ค„์—๋Š” '{product_name}์— ๋Œ€ํ•œ ๋Œ€ํ‘œ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค'๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + "2. ์ตœ๋Œ€ 70์ž ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”.", + "3. ๋ฐ˜๋ณต๋˜๋Š” ๋ฌธ์žฅ์„ ์ค„์ด๊ณ  ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”.", + "4. '์‹œ๊ฐ์žฅ์• ์ธ์ด ์ดํ•ดํ•˜๋„๋ก ์ž‘์„ฑ' ๊ฐ™์€ ํ‘œํ˜„์€ ์ง์ ‘ ์–ธ๊ธ‰ํ•˜์ง€ ๋งˆ์„ธ์š”." + ] + } + ], + "output_requirements": [ + "1. ์ตœ๋Œ€ 70์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.", + "2. ์ค‘๋ณต ํ‘œํ˜„์„ ํ”ผํ•˜๊ณ , ์ง๊ด€์ ์œผ๋กœ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.", + "3. ์‹ค์ œ ์ด๋ฏธ์ง€์™€ ๋ถ€ํ•ฉํ•˜๋Š” ๋‚ด์šฉ์„ ์šฐ์„ ํ•˜์„ธ์š”." + ] +} \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval.py b/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval.py new file mode 100644 index 0000000..bcf9ffa --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval.py @@ -0,0 +1,260 @@ +from utils.common_utils import ( + set_seed, requests, pd, time +) +import yaml +import os +import re +import numpy as np +import matplotlib.pyplot as plt +from concurrent.futures import ThreadPoolExecutor, as_completed + +import openai + +def main(): + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # 2) OpenAI API ํ‚ค ์„ค์ • + openai.api_key = config["openai"]["api_key"] + + # 3) CSV ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • + data_dir = config["paths"]["data_dir"] + output_csv = "outputs/gpt_eval_result_janus+qwen2_5.csv" + + internvl_eval_path = os.path.join(data_dir, config["paths"]["internVL_eval"]) + maai_eval_path = os.path.join(data_dir, config["paths"]["maai_eval"]) + qwen_unsloth_eval_path= os.path.join(data_dir, config["paths"]["unsloth_qwen2_eval"]) + qwen2_eval_path = os.path.join(data_dir, config["paths"]["qwen2_eval"]) + deepseekvl_eval_path = os.path.join(data_dir, config["paths"]["deepseekvl_eval"]) + qwen2_5_eval_path = os.path.join(data_dir, config["paths"]["qwen2.5_eval"]) + janus_eval_path = os.path.join(data_dir, config["paths"]["janus_pro_eval"]) + qwen2_5_janus_eval_path = os.path.join(data_dir, config["paths"]["qwen2_5+janus_eval"]) + + # 4) CSV ๋กœ๋“œ + internvl_eng_eval = pd.read_csv(internvl_eval_path) + maai_eval = pd.read_csv(maai_eval_path) + qwen_unsloth_eval = pd.read_csv(qwen_unsloth_eval_path) + qwen2_eval = pd.read_csv(qwen2_eval_path) + deepseekvl_eval = pd.read_csv(deepseekvl_eval_path) + qwen2_5_eval = pd.read_csv(qwen2_5_eval_path) + janus_eval = pd.read_csv(janus_eval_path) + qwen2_5_janus_eval= pd.read_csv(qwen2_5_janus_eval_path) + + + # 5) GPT ํ‰๊ฐ€ ๋กœ์ง ์ค€๋น„ + def calculate_total_score_from_gpt_eval(eval_text): + """ + GPT๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ํ‰๊ฐ€ ํ…์ŠคํŠธ ๋‚ด์— 'ํ‰๊ฐ€: x/5' ํ˜•ํƒœ์˜ ํ•ญ๋ชฉ์„ ์ •๊ทœ์‹์œผ๋กœ ์ฐพ์•„ + ํ•ฉ๊ณ„๋ฅผ ๊ตฌํ•˜๋Š” ํ•จ์ˆ˜ (10๊ฐœ ํ•ญ๋ชฉ * 0~5์ ). + """ + try: + pattern = r"ํ‰๊ฐ€:\s*([\d\.]+)/5" + scores = [float(match) for match in re.findall(pattern, eval_text)] + return sum(scores) + except Exception as e: + print(f"Error calculating total score: {e}") + return None + + def evaluate_gpt(row): + """ + GPT API ํ˜ธ์ถœ ํ•จ์ˆ˜. + row: pd.Series ํ˜•ํƒœ (์ฃผ์–ด์ง„ CSV ํ•œ ํ–‰) + """ + model_output_text = row.get("Model Output", "") + prompt = f""" + ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ: + {model_output_text} + + ์œ„ ์ •๋ณด๋Š” ์›๋ณธ ์ด๋ฏธ์ง€์™€ ์ด์— ๋Œ€ํ•œ VLM ๋ชจ๋ธ์˜ ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ ํ•ญ๋ชฉ๋“ค์„ ๊ธฐ์ค€์œผ๋กœ ์บก์…˜์˜ ํ’ˆ์งˆ์„ ํ‰๊ฐ€ํ•˜๊ณ , ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์ ์ˆ˜(0-5์ )๋ฅผ ๋ถ€์—ฌํ•œ ํ›„ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ด์ฃผ์„ธ์š”. + + ํ‰๊ฐ€ ํ•ญ๋ชฉ: + 1.ํฌ์žฅ ์šฉ๊ธฐ์˜ ๋ชจ์–‘์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ–ˆ๋Š”๊ฐ€? (0~5์ ) + 2.ํฌ์žฅ ์žฌ์งˆ์ด ์ •ํ™•ํžˆ ํ‘œํ˜„๋˜์—ˆ๋Š”๊ฐ€? (0~5์ ) + 3.๋‚ด์šฉ๋ฌผ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋ช…ํ™•ํžˆ ์ œ์‹œ๋˜์—ˆ๋Š”๊ฐ€? (0~5์ ) + 4.์ƒ‰์ƒ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ํฌํ•จ๋˜์—ˆ๋Š”๊ฐ€? (0~5์ ) + 5.๋””ํ…Œ์ผํ•œ ๋ฌ˜์‚ฌ๊ฐ€ ์ด๋ค„์กŒ๋Š”๊ฐ€? (0~5์ ) + 6.์ œํ’ˆ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š”๊ฐ€? (0~5์ ) + 7.์ œํ’ˆ์˜ ์‹ค์ œ ํŠน์„ฑ์„ ์ •ํ™•ํžˆ ๋ฌ˜์‚ฌํ–ˆ๋Š”๊ฐ€? (์˜คํƒ€๋‚˜ ์™œ๊ณก ์—†๋Š”์ง€) (0~5์ ) + 8.๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ธธ์ง€ ์•Š๊ณ , ํ•ต์‹ฌ ์ •๋ณด์— ์ง‘์ค‘ํ–ˆ๋Š”๊ฐ€? (0~5์ ) + 9.์‹œ๊ฐ์žฅ์• ์ธ์ด ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง๊ด€์ ์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ๋Š”๊ฐ€? (0~5์ ) + 10.ํŠน์ • ์ •๋ณด๋ฅผ ์ค‘๋ณตํ•˜์ง€ ์•Š๊ณ , ์ƒˆ๋กญ๊ฑฐ๋‚˜ ํ•„์š”ํ•œ ์ •๋ณด ์œ„์ฃผ๋กœ ์ •๋ฆฌ๋˜์—ˆ๋Š”๊ฐ€? (0~5์ ) + + ์ ์ˆ˜ ๊ธฐ์ค€(0~5์ ): + 0์ : ์ „ํ˜€ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ + 1์ : ๋งค์šฐ ๋ถ€์กฑํ•˜๊ฒŒ ๋ฐ˜์˜๋จ + 2์ : ์ผ๋ถ€ ๋ฐ˜์˜๋˜์—ˆ์œผ๋‚˜ ๋ถ€์กฑํ•จ + 3์ : ๋ณดํ†ต ์ˆ˜์ค€์œผ๋กœ ๋ฐ˜์˜๋จ + 4์ : ๋Œ€๋ถ€๋ถ„ ์ž˜ ๋ฐ˜์˜๋จ + 5์ : ์™„๋ฒฝํ•˜๊ฒŒ ๋ฐ˜์˜๋จ + + ์ถœ๋ ฅ ์˜ˆ์‹œ: + ํ•ญ๋ชฉ1: 4/5 + ํ”ผ๋“œ๋ฐฑ: ... + ... + (๋งˆ์ง€๋ง‰์— 'ํ‰๊ฐ€: x/5' ํ˜•ํƒœ๋กœ ๊ฐ ํ•ญ๋ชฉ ์ ์ˆ˜ ํ•ฉ๊ณ„๋ฅผ ํ‘œ๊ธฐํ•ด ์ฃผ์„ธ์š”.) + """ + + try: + response = openai.ChatCompletion.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": "๋‹น์‹ ์€ ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค."}, + {"role": "user", "content": prompt} + ], + temperature=0.2, + max_tokens=1024 + ) + gpt_eval_text = response.choices[0].message.content + return gpt_eval_text + except Exception as e: + print(f"Error calling GPT: {e}") + return None + + def run_tasks(df: pd.DataFrame) -> pd.DataFrame: + """ + ThreadPoolExecutor๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ‘๋ ฌ๋กœ GPT ํ‰๊ฐ€ ์ˆ˜ํ–‰. + """ + with ThreadPoolExecutor() as executor: + futures = {} + for idx, row in df.iterrows(): + futures[executor.submit(evaluate_gpt, row)] = idx + + for future in as_completed(futures): + idx = futures[future] + result = future.result() + if result is not None: + df.at[idx, "Eval (gpt-4o)"] = result + df.at[idx, "Score (gpt-4o)"] = calculate_total_score_from_gpt_eval(result) + return df + + # 6) ๊ฐ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์— ๋Œ€ํ•ด์„œ GPT ํ‰๊ฐ€ ์ถ”๊ฐ€ ("Score (gpt-4o)" ์—ด) + internvl_eng_eval = run_tasks(internvl_eng_eval) + maai_eval = run_tasks(maai_eval) + deepseekvl_eval = run_tasks(deepseekvl_eval) + qwen_unsloth_eval = run_tasks(qwen_unsloth_eval) + qwen2_eval = run_tasks(qwen2_eval) + qwen2_5_eval = run_tasks(qwen2_5_eval) + janus_eval = run_tasks(janus_eval) + qwen2_5_janus_eval= run_tasks(qwen2_5_janus_eval) + + # 7) CSV๋กœ ๋‹ค์‹œ ์ €์žฅ (์›ํ•˜๋ฉด overwrite or new filename) + internvl_eng_eval.to_csv(internvl_eval_path, index=False, encoding='utf-8-sig') + maai_eval.to_csv(maai_eval_path, index=False, encoding='utf-8-sig') + deepseekvl_eval.to_csv(deepseekvl_eval_path, index=False, encoding='utf-8-sig') + qwen_unsloth_eval.to_csv(qwen_unsloth_eval_path, index=False, encoding='utf-8-sig') + qwen2_eval.to_csv(qwen2_eval_path, index=False, encoding='utf-8-sig') + qwen2_5_eval.to_csv(qwen2_5_eval_path, index=False, encoding='utf-8-sig') + janus_eval.to_csv(janus_eval_path, index=False, encoding='utf-8-sig') + qwen2_5_janus_eval.to_csv(qwen2_5_janus_eval_path, index=False, encoding='utf-8-sig') + + print("[Info] GPT-4o Evaluation columns added to each CSV successfully.") + + # 8) ๋ชจ๋ธ๋ณ„ ์ ์ˆ˜ ํ•ฉ ๊ณ„์‚ฐ + internvl_eng_total_score_gpt_4o = internvl_eng_eval['Score (gpt-4o)'].sum() + maai_total_score_gpt_4o = maai_eval['Score (gpt-4o)'].sum() + deepseekvl_total_score_gpt_4o = deepseekvl_eval['Score (gpt-4o)'].sum() + qwen2_unsloth_total_score_gpt_4o= qwen_unsloth_eval['Score (gpt-4o)'].sum() + qwen2_total_score_gpt_4o = qwen2_eval['Score (gpt-4o)'].sum() + qwen2_5_total_score_gpt_4o = qwen2_5_eval['Score (gpt-4o)'].sum() + janus_total_score_gpt_4o = janus_eval['Score (gpt-4o)'].sum() + qwen2_5_janus_total_score_gpt_4o= qwen2_5_janus_eval['Score (gpt-4o)'].sum() + + print(f"internvl_eng Score (gpt-4o): {internvl_eng_total_score_gpt_4o}") + print(f"maai Score (gpt-4o): {maai_total_score_gpt_4o}") + print(f"deepseekvl Score (gpt-4o): {deepseekvl_total_score_gpt_4o}") + print(f"qwen2_unsloth Score (gpt-4o): {qwen2_unsloth_total_score_gpt_4o}") + print(f"qwen2 Score (gpt-4o): {qwen2_total_score_gpt_4o}") + print(f"qwen2_5 Score (gpt-4o): {qwen2_5_total_score_gpt_4o}") + print(f"janus Score (gpt-4o): {janus_total_score_gpt_4o}") + print(f"qwen2_5_janus Score (gpt-4o): {qwen2_5_janus_total_score_gpt_4o}") + + # 9) ํ‰๊ท  ์ถ”๋ก  ์‹œ๊ฐ„ ๊ณ„์‚ฐ + internvl_eng_avg_time = internvl_eng_eval['Inference Time (s)'].mean() + maai_avg_time = maai_eval['Inference Time (s)'].mean() + deepseekvl_avg_time = deepseekvl_eval['Inference Time (s)'].mean() + qwen2_unsloth_avg_time= qwen_unsloth_eval['Inference Time (s)'].mean() + qwen2_avg_time = qwen2_eval['Inference Time (s)'].mean() + qwen2_5_avg_time = qwen2_5_eval['Inference Time (s)'].mean() + janus_avg_time = janus_eval['Inference Time (s)'].mean() + qwen2_5_janus_avg_time= qwen2_5_janus_eval['Inference Time (s)'].mean() + + print(f"internvl Avg Inference Time: {internvl_eng_avg_time:.2f}") + print(f"maai Avg Inference Time: {maai_avg_time:.2f}") + print(f"deepseekvl Avg Inference Time: {deepseekvl_avg_time:.2f}") + print(f"qwen2(unsloth) Avg Inference Time: {qwen2_unsloth_avg_time:.2f}") + print(f"qwen2 Avg Inference Time: {qwen2_avg_time:.2f}") + print(f"qwen2_5 Avg Inference Time: {qwen2_5_avg_time:.2f}") + print(f"janus Avg Inference Time: {janus_avg_time:.2f}") + print(f"qwen2_5_janus Avg Inference Time: {qwen2_5_janus_avg_time:.2f}") + + # 10) ์‹œ๊ฐํ™” ํŒŒํŠธ + # Performance Comparison + models = ['MAAI','InternVL','Qwen2_VL(Unsloth)','Qwen2_VL','DeepSeek_VL','Qwen2_5_VL','Janus_Pro','Qwen2_5_Janus' ] + total_scores_gpt_4o = [ + maai_total_score_gpt_4o, + internvl_eng_total_score_gpt_4o, + qwen2_unsloth_total_score_gpt_4o, + qwen2_total_score_gpt_4o, + deepseekvl_total_score_gpt_4o, + qwen2_5_total_score_gpt_4o, + janus_total_score_gpt_4o, + qwen2_5_janus_total_score_gpt_4o + ] + # 10๊ฐœ ํ•ญ๋ชฉ * 5์  ๋งŒ์  * N๊ฐœ ๋ฐ์ดํ„ฐ?? ์˜ˆ: 50๊ฐœ, => 2500์  = 100% + total_scores_gpt_4o_percent = [(val / 2500) * 100 for val in total_scores_gpt_4o] + + colors = ['#FF7F50', '#008080', '#E6E6FA', '#FFD700', '#DDA0DD', '#6A5ACD', '#32CD32', '#DC143C'] + fig, ax = plt.subplots(figsize=(12, 8)) + bars = ax.bar(models, total_scores_gpt_4o_percent, color=colors, width=0.6) + for bar in bars: + h = bar.get_height() + ax.text(bar.get_x() + bar.get_width()/2., h, + f'{h:.2f} %', + ha='center', va='bottom', fontsize=12, fontweight='bold') + ax.set_ylabel('Total Score (%)', fontsize=14, fontweight='bold') + ax.set_title('Model Performance Comparison (gpt-4o)', fontsize=18, fontweight='bold', pad=20) + ax.set_ylim(0, max(total_scores_gpt_4o_percent) * 1.2) + ax.grid(axis='y', linestyle='--', alpha=0.7) + plt.xticks(rotation=0, ha='center', fontsize=12, fontweight='bold') + plt.yticks(fontsize=10) + for bar in bars: + bar.set_edgecolor('white') + bar.set_linewidth(2) + plt.tight_layout() + plt.savefig('model_performance_comparison_8.png', dpi=300, bbox_inches='tight') + plt.show() + + # Inference Time Comparison + avg_times = [ + maai_avg_time, + internvl_eng_avg_time, + qwen2_unsloth_avg_time, + qwen2_avg_time, + deepseekvl_avg_time, + qwen2_5_avg_time, + janus_avg_time, + qwen2_5_janus_avg_time + ] + fig2, ax2 = plt.subplots(figsize=(12, 8)) + bars2 = ax2.bar(models, avg_times, color=colors, width=0.6) + for bar in bars2: + h = bar.get_height() + ax2.text(bar.get_x() + bar.get_width()/2., h, + f'{h:.2f} (s)', + ha='center', va='bottom', fontsize=12, fontweight='bold') + ax2.set_ylabel('Avg Inference Time (s)', fontsize=14, fontweight='bold') + ax2.set_title('Model Avg Inference Time Comparison', fontsize=18, fontweight='bold', pad=20) + ax2.set_ylim(0, max(avg_times) * 1.2) + ax2.grid(axis='y', linestyle='--', alpha=0.7) + plt.xticks(rotation=0, ha='center', fontsize=12, fontweight='bold') + plt.yticks(fontsize=10) + for bar in bars2: + bar.set_edgecolor('white') + bar.set_linewidth(2) + plt.tight_layout() + plt.savefig('model_avg_inference_time_comparison_8.png', dpi=300, bbox_inches='tight') + plt.show() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval_323.py b/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval_323.py new file mode 100644 index 0000000..77d6022 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/evaluation/gpt_eval_323.py @@ -0,0 +1,162 @@ +from utils.common_utils import ( + set_seed, requests, pd, time +) +import yaml +import os +import re +import numpy as np +import matplotlib.pyplot as plt +from concurrent.futures import ThreadPoolExecutor, as_completed + +def main(): + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # 2) OpenAI API Key ์„ค์ • + openai.api_key = config["openai"]["api_key"] + + # 3) CSV ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • + data_dir = config["paths"]["data_dir"] + qwen2_5_janus_323_eval_path = os.path.join(data_dir, config["paths"]["qwen2_5+janus_323_eval"]) + output_csv = "outputs/gpt_eval_result_janus+qwen2_5.csv" # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ CSV ํŒŒ์ผ๋ช… + + # 4) CSV ํŒŒ์ผ ๋กœ๋“œ + df = pd.read_csv(qwen2_5_janus_323_eval_path) + print("Data loaded:", df.shape) + + ### GPT ํ‰๊ฐ€ ๋กœ์ง ### + + def calculate_total_score_from_gpt_eval(eval_text): + """ + GPT๊ฐ€ ์ƒ์„ฑํ•œ ํ‰๊ฐ€ ํ…์ŠคํŠธ์—์„œ 'ํ‰๊ฐ€: x/5' ํ˜•ํƒœ๋กœ ๋œ ์ˆซ์ž๋ฅผ ์ฐพ์•„ + ํ•ฉ์‚ฐํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ (10๊ฐœ ํ•ญ๋ชฉ * 0~5์ ). + """ + try: + pattern = r"ํ‰๊ฐ€:\s*([\d\.]+)/5" + matches = re.findall(pattern, eval_text) + scores = [float(m) for m in matches] + return sum(scores) + except Exception as e: + print(f"Error calculating total score: {e}") + return None + + def evaluate_gpt(model_name, idx, row): + model_output = row.get("Model Output", "") + prompt = f""" + ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ: + {model_output} + + ์œ„ ์ •๋ณด๋Š” ์›๋ณธ ์ด๋ฏธ์ง€์™€ ์ด์— ๋Œ€ํ•œ VLM ๋ชจ๋ธ์˜ ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. + ์•„๋ž˜ ํ•ญ๋ชฉ๋“ค์„ ๊ธฐ์ค€์œผ๋กœ ์บก์…˜์˜ ํ’ˆ์งˆ์„ ํ‰๊ฐ€ํ•˜๊ณ , ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์ ์ˆ˜(0-5์ )๋ฅผ ๋ถ€์—ฌํ•œ ํ›„ + ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ด์ฃผ์„ธ์š”. + + ํ‰๊ฐ€ ํ•ญ๋ชฉ: + 1.ํฌ์žฅ ์šฉ๊ธฐ์˜ ๋ชจ์–‘์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ–ˆ๋Š”๊ฐ€? (์˜ˆ: ์ง์‚ฌ๊ฐํ˜•, ์›ํ˜•, ๋น„๋‹ํ˜•, ์ •์‚ฌ๊ฐํ˜• ๋“ฑ) + 2.ํฌ์žฅ ์žฌ์งˆ์ด ์ •ํ™•ํžˆ ํ‘œํ˜„๋˜์—ˆ๋Š”๊ฐ€? (์˜ˆ: ์ข…์ด, ํ”Œ๋ผ์Šคํ‹ฑ, ๋น„๋‹, ํŽ˜ํŠธ๋ณ‘, ์บ”, ์œ ๋ฆฌ ๋“ฑ) + 3.๋‚ด์šฉ๋ฌผ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋ช…ํ™•ํžˆ ์ œ์‹œ๋˜์—ˆ๋Š”๊ฐ€? (์˜ˆ: ๊ณผ์ž, ์ƒ์„ , ๊ณผ์ผ ๋“ฑ) + 4.ํŒจํ‚ค์ง€์— ๋Œ€ํ•œ ๋ฌ˜์‚ฌ๊ฐ€ ์ด๋ค„์กŒ๋Š”๊ฐ€? + 5.์ƒ‰์ƒ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ํฌํ•จ๋˜์—ˆ๋Š”๊ฐ€? (์˜ˆ: ๋นจ๊ฐ„์ƒ‰ ๋šœ๊ป‘, ํˆฌ๋ช…ํ•œ ๋ณ‘, ์ดˆ๋ก์ƒ‰ ํฌ์žฅ์ง€ ๋“ฑ) + 6.์ œํ’ˆ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š”๊ฐ€? (ํ•ด๋‹น ์ œํ’ˆ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ๋‹ด๊ฒจ ์žˆ๋Š”์ง€) + 7.์ œํ’ˆ์˜ ์‹ค์ œ ํŠน์„ฑ์„ ์ •ํ™•ํžˆ ๋ฌ˜์‚ฌํ–ˆ๋Š”๊ฐ€? (์˜คํƒ€๋‚˜ ์™œ๊ณก๋œ ์ •๋ณด๊ฐ€ ์—†๋Š”์ง€) + 8.์บก์…˜์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ธธ์ง€ ์•Š๊ณ , ํ•ต์‹ฌ ์ •๋ณด์— ์ง‘์ค‘ํ–ˆ๋Š”๊ฐ€? + 9.์‹œ๊ฐ์žฅ์• ์ธ์ด ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช…ํ™•ํ•˜๊ณ  ์ง๊ด€์ ์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ๋Š”๊ฐ€? + 10.ํŠน์ • ์ •๋ณด๋ฅผ ์ค‘๋ณตํ•˜์ง€ ์•Š๊ณ , ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ์ •๋ณด ์œ„์ฃผ๋กœ ์ •๋ฆฌ๋˜์—ˆ๋Š”๊ฐ€? + + ์ ์ˆ˜ ๊ธฐ์ค€(0~5์ ): + 0์ : ์ „ํ˜€ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ + 1์ : ๋งค์šฐ ๋ถ€์กฑํ•˜๊ฒŒ ๋ฐ˜์˜๋จ + 2์ : ์ผ๋ถ€ ๋ฐ˜์˜๋˜์—ˆ์œผ๋‚˜ ๋ถ€์กฑํ•จ + 3์ : ๋ณดํ†ต ์ˆ˜์ค€์œผ๋กœ ๋ฐ˜์˜๋จ + 4์ : ๋Œ€๋ถ€๋ถ„ ์ž˜ ๋ฐ˜์˜๋จ + 5์ : ์™„๋ฒฝํ•˜๊ฒŒ ๋ฐ˜์˜๋จ + + ์ถœ๋ ฅ ํ˜•์‹ ์˜ˆ์‹œ: + ํ•ญ๋ชฉ: 1.์บก์…˜์ด ํฌ์žฅ ์šฉ๊ธฐ์˜ ๋ชจ์–‘์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ–ˆ๋Š”๊ฐ€? + ํ‰๊ฐ€: 4/5 + ํ”ผ๋“œ๋ฐฑ: ๋ชจ์–‘์ด ๋Œ€๋ถ€๋ถ„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฌ˜์‚ฌ๋˜์—ˆ์œผ๋‚˜, ์•ฝ๊ฐ„์˜ ์„ธ๋ถ€ ์ •๋ณด๊ฐ€ ๋ถ€์กฑํ•จ. + (๋งˆ์ง€๋ง‰์— ๊ฐ ํ•ญ๋ชฉ ์ ์ˆ˜ ํ•ฉ๊ณ„๋ฅผ 'ํ‰๊ฐ€: x/5' ํ˜•ํƒœ๋กœ ํ‘œ๊ธฐํ•ด์ฃผ์„ธ์š”.) + """ + try: + completion = openai.ChatCompletion.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": "๋‹น์‹ ์€ VLM์˜ ์ด๋ฏธ์ง€ ์บก์…”๋‹ ๊ฒฐ๊ณผ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค."}, + {"role": "user", "content": prompt} + ], + temperature=0.2, + max_tokens=1024 + ) + gpt_eval = completion.choices[0].message.content + return idx, gpt_eval + except Exception as e: + print(f"Error for idx {idx}: {e}") + return idx, None + + def run_tasks(df_input, model_name): + from concurrent.futures import ThreadPoolExecutor, as_completed + futures = {} + with ThreadPoolExecutor() as executor: + for i, row in df_input.iterrows(): + futures[executor.submit(evaluate_gpt, model_name, i, row)] = i + + for future in as_completed(futures): + idx = futures[future] + res = future.result() + if res is not None: + row_idx, gpt_eval_text = res + if gpt_eval_text: + df_input.at[row_idx, f'Eval ({model_name})'] = gpt_eval_text + df_input.at[row_idx, f'Score ({model_name})'] = calculate_total_score_from_gpt_eval(gpt_eval_text) + return df_input + + # 5) GPT ํ‰๊ฐ€ ์‹คํ–‰ + model_name = "gpt-4o" + df_eval = run_tasks(df, model_name) + + # 6) ๊ฒฐ๊ณผ CSV ์ €์žฅ + df_eval.to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[Info] GPT Evaluation completed and saved => {output_csv}") + + # 7) ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ์šฉ ์ ์ˆ˜ ์ค€๋น„ + # ์ ์ˆ˜ ํ•ฉ ๊ณ„์‚ฐ + sum_score = df_eval[f'Score ({model_name})'].sum() + print(f"Total Score (gpt-4o) = {sum_score}") + + # ๋ชจ๋ธ๋ช… ๋ฆฌ์ŠคํŠธ์™€ ์ ์ˆ˜ ๋ฆฌ์ŠคํŠธ + models = ['Janus_Qwen2_5'] + + # ์˜ˆ: 10๊ฐœ ํ•ญ๋ชฉ * 5์  ๋งŒ์  * N๊ฐœ ๋ฐ์ดํ„ฐ = 10*N*5 => ์ตœ๋Œ€์น˜ + max_possible_score = 10 * df_eval.shape[0] * 5 + # ์ ์ˆ˜ % ๊ณ„์‚ฐ + percentage = (sum_score / max_possible_score) * 100 + scores_gpt_4o = [percentage] + + # ๊ทธ๋ž˜ํ”„ + colors = ['#FF7F50'] + + fig, ax = plt.subplots(figsize=(8, 6)) + bars = ax.bar(models, scores_gpt_4o, color=colors, width=0.6) + for bar in bars: + height = bar.get_height() + ax.text(bar.get_x() + bar.get_width()/2., height, + f'{height:.2f} %', + ha='center', va='bottom', fontsize=12, fontweight='bold') + + ax.set_ylabel('Total Score (%)', fontsize=14, fontweight='bold') + ax.set_title('Model Performance Comparison (GPT-4o)', fontsize=18, fontweight='bold', pad=20) + ax.set_ylim(0, max(scores_gpt_4o) * 1.2 if len(scores_gpt_4o) > 0 else 100) + ax.grid(axis='y', linestyle='--', alpha=0.7) + plt.xticks(rotation=0, ha='center', fontsize=12, fontweight='bold') + plt.yticks(fontsize=10) + + for bar in bars: + bar.set_edgecolor('white') + bar.set_linewidth(2) + + plt.tight_layout() + plt.savefig('model_performance_comparison_total.png', dpi=300, bbox_inches='tight') + print("[Info] Bar chart saved => model_performance_comparison_total.png") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/deepseekvl.py b/models/thumbnail_description/src/description_pipeline/inference_model/deepseekvl.py new file mode 100644 index 0000000..ec034e9 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/deepseekvl.py @@ -0,0 +1,134 @@ +import os +import time +import urllib.request +import pandas as pd +import torch +import yaml + +from transformers import AutoModelForCausalLM +from deepseek_vl.models import VLChatProcessor, MultiModalityCausalLM +from deepseek_vl.utils.io import load_pil_images + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_deepseekvl(): + """ + DeepSeek-VL-7B-Chat ๋ชจ๋ธ์„ ํ™œ์šฉํ•œ ์ถ”๋ก  ์Šคํฌ๋ฆฝํŠธ. + config.yaml์„ ํ†ตํ•ด CSV ๊ฒฝ๋กœ, ํ”„๋กฌํ”„ํŠธ ๊ฒฝ๋กœ, ๊ฒฐ๊ณผ ์ €์žฅ ๊ฒฝ๋กœ๋ฅผ ์ฝ์–ด์˜จ ๋’ค ์ž‘์—… ์ˆ˜ํ–‰. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["deepseekvl_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "deepseek_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) DeepSeek ๋ชจ๋ธ ์ค€๋น„ + model_path = "deepseek-ai/deepseek-vl-7b-chat" + vl_chat_processor = VLChatProcessor.from_pretrained(model_path) + tokenizer = vl_chat_processor.tokenizer + + vl_gpt = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True) + vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval() + + model_name = "deepseek-ai/deepseek-vl-7b-chat" + + def process_image(image_url, prompt): + """ + ๊ฐœ๋ณ„ ์ด๋ฏธ์ง€ URL์— ๋Œ€ํ•ด DeepSeek-VL ๋ชจ๋ธ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜. + """ + # ์ž„์‹œ ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ๋ช… + temp_filename = "temp_deepseek.jpg" + + # ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ + urllib.request.urlretrieve(image_url, temp_filename) + try: + # ๋Œ€ํ™” ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ + conversation = [ + { + "role": "User", + "content": f"\n{prompt}", + "images": [temp_filename] + }, + { + "role": "Assistant", + "content": "" + } + ] + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + pil_images = load_pil_images(conversation) + + # ์ž…๋ ฅ ์ค€๋น„ + prepare_inputs = vl_chat_processor( + conversations=conversation, images=pil_images, force_batchify=True + ).to(vl_gpt.device) + + # ์ด๋ฏธ์ง€ ์ž„๋ฒ ๋”ฉ + inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs) + + # ํ…์ŠคํŠธ ์ƒ์„ฑ + outputs = vl_gpt.language_model.generate( + inputs_embeds=inputs_embeds, + attention_mask=prepare_inputs.attention_mask, + pad_token_id=tokenizer.eos_token_id, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, + max_new_tokens=512, + do_sample=True, + temperature=0.2, + top_p=0.95 + ) + answer = tokenizer.decode(outputs[0].cpu().tolist(), skip_special_tokens=True) + + print(f"{prepare_inputs['sft_format'][0]}", answer) + return answer + except Exception as e: + print(f"Error processing image at {image_url}: {e}") + return "Error: An unexpected error occurred." + finally: + # ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ ์‚ญ์ œ(ํ•„์š” ์‹œ) + if os.path.exists(temp_filename): + os.remove(temp_filename) + + # 6) ๋ฐ˜๋ณต ์ถ”๋ก  + results = [] + for idx, (image_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + + prompt = base_prompt + + output = process_image(image_url, prompt) + elapsed = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": image_url, + "Prompt": prompt, + "Inference Time (s)": elapsed, + "Model Output": output + }) + + print(f"[{idx+1}/{len(image_urls)}] Processed in {elapsed:.2f}s => {product_name}") + + # 7) ๊ฒฐ๊ณผ ์ €์žฅ + pd.DataFrame(results).to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[DeepSeek-VL] Saved results => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/finetuned_janus_pro.py b/models/thumbnail_description/src/description_pipeline/inference_model/finetuned_janus_pro.py new file mode 100644 index 0000000..67ae18e --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/finetuned_janus_pro.py @@ -0,0 +1,110 @@ +import os +import time +import urllib.request +import pandas as pd +import torch +import yaml + +from transformers import AutoModelForCausalLM +from janus.models import MultiModalityCausalLM, VLChatProcessor +from janus.utils.io import load_pil_images + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_janus_pro(): + """ + itsmenlp/finetuned-Janus-Pro-7B ๋ชจ๋ธ ์ถ”๋ก  ํ›„ ๊ฒฐ๊ณผ CSV ์ €์žฅ. + config.yaml์„ ์ฐธ๊ณ ํ•˜์—ฌ CSV, ํ”„๋กฌํ”„ํŠธ, ๊ฒฐ๊ณผ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["janus_pro_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "janus_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ์ฝ๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) Janus-Pro ๋ชจ๋ธ ์ค€๋น„ + model_path = "itsmenlp/finetuned-Janus-Pro-7B" #private + vl_chat_processor = VLChatProcessor.from_pretrained(model_path) + tokenizer = vl_chat_processor.tokenizer + + vl_gpt = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True) + vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval() + + model_name = "itsmenlp/finetuned-Janus-Pro-7B" + + def process_image(img_url, prompt): + temp_filename = "temp_janus.jpg" + urllib.request.urlretrieve(img_url, temp_filename) + try: + conversation = [ + {"role": "<|User|>", "content": f"\n{prompt}", "images": [temp_filename]}, + {"role": "<|Assistant|>", "content": ""} + ] + pil_images = load_pil_images(conversation) + prepare_inputs = vl_chat_processor( + conversations=conversation, images=pil_images, force_batchify=True + ).to(vl_gpt.device) + + inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs) + outputs = vl_gpt.language_model.generate( + inputs_embeds=inputs_embeds, + attention_mask=prepare_inputs.attention_mask, + pad_token_id=tokenizer.eos_token_id, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, + max_new_tokens=512, + do_sample=True, + temperature=0.2, + top_p=0.95 + ) + answer = tokenizer.decode(outputs[0].cpu().tolist(), skip_special_tokens=True) + return answer + except Exception as e: + print(f"Error processing image at {img_url}: {e}") + return "Error: An unexpected error occurred." + finally: + if os.path.exists(temp_filename): + os.remove(temp_filename) + + # 6) ๋ฐ˜๋ณต ์ถ”๋ก  + results = [] + for idx, (image_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + prompt = base_prompt + + output = process_image(image_url, prompt) + elapsed_time = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": image_url, + "Prompt": prompt, + "Inference Time (s)": elapsed_time, + "Model Output": output + }) + + print(f"[JanusPro] Processed {idx+1}/{len(image_urls)} in {elapsed_time:.2f}s => {product_name}") + + # 7) ๊ฒฐ๊ณผ ์ €์žฅ + pd.DataFrame(results).to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[JanusPro] Saved results => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/janus_pro.py b/models/thumbnail_description/src/description_pipeline/inference_model/janus_pro.py new file mode 100644 index 0000000..e380481 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/janus_pro.py @@ -0,0 +1,110 @@ +import os +import time +import urllib.request +import pandas as pd +import torch +import yaml + +from transformers import AutoModelForCausalLM +from janus.models import MultiModalityCausalLM, VLChatProcessor +from janus.utils.io import load_pil_images + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_janus_pro(): + """ + Janus-Pro-7B ๋ชจ๋ธ ์ถ”๋ก  ํ›„ ๊ฒฐ๊ณผ CSV ์ €์žฅ. + config.yaml์„ ์ฐธ๊ณ ํ•˜์—ฌ CSV, ํ”„๋กฌํ”„ํŠธ, ๊ฒฐ๊ณผ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["janus_pro_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "janus_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ์ฝ๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) Janus-Pro ๋ชจ๋ธ ์ค€๋น„ + model_path = "deepseek-ai/Janus-Pro-7B" + vl_chat_processor = VLChatProcessor.from_pretrained(model_path) + tokenizer = vl_chat_processor.tokenizer + + vl_gpt = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True) + vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval() + + model_name = "deepseek-ai/Janus-Pro-7B" + + def process_image(img_url, prompt): + temp_filename = "temp_janus.jpg" + urllib.request.urlretrieve(img_url, temp_filename) + try: + conversation = [ + {"role": "<|User|>", "content": f"\n{prompt}", "images": [temp_filename]}, + {"role": "<|Assistant|>", "content": ""} + ] + pil_images = load_pil_images(conversation) + prepare_inputs = vl_chat_processor( + conversations=conversation, images=pil_images, force_batchify=True + ).to(vl_gpt.device) + + inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs) + outputs = vl_gpt.language_model.generate( + inputs_embeds=inputs_embeds, + attention_mask=prepare_inputs.attention_mask, + pad_token_id=tokenizer.eos_token_id, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, + max_new_tokens=512, + do_sample=True, + temperature=0.2, + top_p=0.95 + ) + answer = tokenizer.decode(outputs[0].cpu().tolist(), skip_special_tokens=True) + return answer + except Exception as e: + print(f"Error processing image at {img_url}: {e}") + return "Error: An unexpected error occurred." + finally: + if os.path.exists(temp_filename): + os.remove(temp_filename) + + # 6) ๋ฐ˜๋ณต ์ถ”๋ก  + results = [] + for idx, (image_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + prompt = base_prompt + + output = process_image(image_url, prompt) + elapsed_time = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": image_url, + "Prompt": prompt, + "Inference Time (s)": elapsed_time, + "Model Output": output + }) + + print(f"[JanusPro] Processed {idx+1}/{len(image_urls)} in {elapsed_time:.2f}s => {product_name}") + + # 7) ๊ฒฐ๊ณผ ์ €์žฅ + pd.DataFrame(results).to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[JanusPro] Saved results => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/maal.py b/models/thumbnail_description/src/description_pipeline/inference_model/maal.py new file mode 100644 index 0000000..66b638b --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/maal.py @@ -0,0 +1,127 @@ +import os +import time +import re +import requests +import torch +import pandas as pd +import yaml +from PIL import Image + +from transformers import MllamaForConditionalGeneration, AutoProcessor +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_maal(): + """ + MAAL ๋ชจ๋ธ ์ถ”๋ก  ํ›„ CSV ํŒŒ์ผ์— ์ €์žฅ. + config.yaml์„ ์ฐธ๊ณ ํ•˜์—ฌ CSV, ํ”„๋กฌํ”„ํŠธ, ๊ฒฐ๊ณผ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["maai_pro_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "maal_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) MAAL ๋ชจ๋ธ ์ค€๋น„ + model_id = "maum-ai/Llama-3.2-MAAL-11B-Vision-v0.1" + print("[MAAL] Loading model...") + model = MllamaForConditionalGeneration.from_pretrained( + model_id, + torch_dtype=torch.float16, + device_map="auto", + ) + processor = AutoProcessor.from_pretrained(model_id) + + # ๋ชจ๋ธ output embeddings ์กฐ์ • + old_embeddings = model.get_output_embeddings() + num_tokens = model.vocab_size + 1 + resized_embeddings = model._get_resized_lm_head(old_embeddings, new_num_tokens=num_tokens, mean_resizing=True) + resized_embeddings.requires_grad_(old_embeddings.weight.requires_grad) + model.set_output_embeddings(resized_embeddings) + + model_name = "maai" + results = [] + + def process_image_with_maai(img_url, prompt): + try: + # ์ด๋ฏธ์ง€ ๋กœ๋“œ (HTTP GET ํ›„ PIL Image ๋ณ€ํ™˜) + image = Image.open(requests.get(img_url, stream=True).raw) + + # ๋ฉ”์‹œ์ง€ ๊ตฌ์„ฑ (์œ ์ € ์—ญํ• ์— [์ด๋ฏธ์ง€ + ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ]) + messages = [ + {"role": "user", "content": [ + {"type": "image"}, + {"type": "text", "text": prompt} + ]} + ] + # chat ํ…œํ”Œ๋ฆฟ ์ ์šฉ + input_text = processor.apply_chat_template(messages, add_generation_prompt=True) + inputs = processor( + image, + input_text, + add_special_tokens=False, + return_tensors="pt" + ).to(model.device) + + # ๋ชจ๋ธ ์ถ”๋ก  + output = model.generate( + **inputs, + max_new_tokens=256, + no_repeat_ngram_size=3, + do_sample=False + ) + result = processor.decode(output[0]) + + # ์ •๊ทœ์‹์œผ๋กœ MAAL ๋ชจ๋ธ ๊ฒฐ๊ณผ์—์„œ assistant ๋ถ€๋ถ„ ์ถ”์ถœ + pattern = r"<\|start_header_id\|>assistant<\|end_header_id\|>\n\n(.+?)(?:<\|eot_id\|>|$)" + match = re.search(pattern, result, re.DOTALL) + if match: + return match.group(1).strip() + else: + return "No match found" + except Exception as e: + print(f"Error processing image at {img_url}: {e}") + return "Error" + + # 6) ๊ฐ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์ถ”๋ก  ์ˆ˜ํ–‰ + for idx, (image_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + # prompt์— {product_name} ์น˜ํ™˜ (ํ•„์š” ์‹œ) + prompt = base_prompt.replace("{product_name}", product_name) + + output = process_image_with_maai(image_url, prompt) + elapsed_time = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": image_url, + "Prompt": prompt[:100], # ๊ธธ์ด ์ œํ•œ + "Inference Time (s)": elapsed_time, + "Model Output": output + }) + + print(f"[MAAL] Processed {idx+1}/{len(image_urls)} => {elapsed_time:.2f}s => {product_name}") + + # 7) ๊ฒฐ๊ณผ๋ฅผ CSV๋กœ ์ €์žฅ + df = pd.DataFrame(results) + df.to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[MAAL] Results saved => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_5_vl.py b/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_5_vl.py new file mode 100644 index 0000000..09eda50 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_5_vl.py @@ -0,0 +1,123 @@ +import os +import time +import yaml +import pandas as pd +import torch + +from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor +from qwen_vl_utils import process_vision_info + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_qwen2_5_vl(): + """ + Qwen2.5-VL-7B-Instruct ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด CSV ๋ฐ์ดํ„ฐ ๋‚ด ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด + ์ถ”๋ก  ํ›„ ๊ฒฐ๊ณผ CSV๋ฅผ ์ €์žฅ. + config.yaml์„ ์ฐธ๊ณ ํ•˜์—ฌ ๊ฒฝ๋กœ(์ž…๋ ฅ/ํ”„๋กฌํ”„ํŠธ/์ถœ๋ ฅ)๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["qwen2.5_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "qwen2_5_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) ๋ชจ๋ธ ๋กœ๋”ฉ + print("[Qwen2.5-VL] Loading model...") + model = Qwen2_5_VLForConditionalGeneration.from_pretrained( + "Qwen/Qwen2.5-VL-7B-Instruct", torch_dtype="auto", device_map="auto" + ) + + # Qwen2.5-VL ๋ชจ๋ธ์˜ ์‹œ๊ฐ ํ† ํฐ ๋ฒ”์œ„ ์„ค์ • + min_pixels = 256 * 28 * 28 + max_pixels = 1280 * 28 * 28 + processor = AutoProcessor.from_pretrained( + "Qwen/Qwen2.5-VL-7B-Instruct", min_pixels=min_pixels, max_pixels=max_pixels + ) + + model_name = "qwen2.5" + results = [] + + def process_qwen2_5_vl(img_url, prompt_text): + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€ URL๊ณผ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ด์šฉํ•ด Qwen2.5-VL ๋ชจ๋ธ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜. + """ + try: + # ๋ฉ”์‹œ์ง€(์œ ์ € ์—ญํ• ) ๊ตฌ์„ฑ + messages = [ + { + "role": "user", + "content": [ + {"type": "image", "image": img_url}, + {"type": "text", "text": prompt_text}, + ], + } + ] + # ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ ์ ์šฉ + input_text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) + image_inputs, video_inputs = process_vision_info(messages) + + # ๋ชจ๋ธ ์ž…๋ ฅ + inputs = processor( + text=[input_text], + images=image_inputs, + videos=video_inputs, + padding=True, + return_tensors="pt", + ).to("cuda") + + # ํ…์ŠคํŠธ ์ƒ์„ฑ + generated_ids = model.generate(**inputs, max_new_tokens=512) + generated_ids_trimmed = [ + out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids) + ] + output_text = processor.batch_decode( + generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False + ) + return output_text[0] + except Exception as e: + print(f"Error processing image at {img_url}: {e}") + return "Error" + + # 6) ๋ฐ˜๋ณต ์ถ”๋ก  + for idx, (img_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + + prompt = base_prompt.replace("{product_name}", product_name) + + output = process_qwen2_5_vl(img_url, prompt) + elapsed_time = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": img_url, + "Prompt": prompt + "Inference Time (s)": elapsed_time, + "Model Output": output + }) + + print(f"[Qwen2.5-VL] {idx+1}/{len(image_urls)} => {elapsed_time:.2f}s => {product_name}") + + # 7) ๊ฒฐ๊ณผ ์ €์žฅ + df = pd.DataFrame(results) + df.to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[Qwen2.5-VL] Results => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_vl.py b/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_vl.py new file mode 100644 index 0000000..b4ce82a --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/qwen2_vl.py @@ -0,0 +1,124 @@ +import os +import time +import yaml +import pandas as pd +import torch + +from transformers import Qwen2VLForConditionalGeneration, AutoProcessor +from qwen_vl_utils import process_vision_info + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_qwen2_vl(): + """ + Qwen2-VL-7B-Instruct ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜์—ฌ CSV ๋ฐ์ดํ„ฐ ๋‚ด ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด + ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•œ ๋’ค ๊ฒฐ๊ณผ๋ฅผ CSV ํŒŒ์ผ์— ์ €์žฅ. + config.yaml์—์„œ ๊ฒฝ๋กœ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["qwen2_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "qwen2_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # ํ”„๋กฌํ”„ํŠธ ์ฝ๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + print("[Qwen2-VL] Loading model and processor...") + model = Qwen2VLForConditionalGeneration.from_pretrained( + "Qwen/Qwen2-VL-7B-Instruct", torch_dtype="auto", device_map="auto" + ) + # ์ด๋ฏธ์ง€ ํ† ํฐํ™” ํŒŒ๋ผ๋ฏธํ„ฐ + min_pixels = 256 * 28 * 28 + max_pixels = 1280 * 28 * 28 + processor = AutoProcessor.from_pretrained( + "Qwen/Qwen2-VL-7B-Instruct", min_pixels=min_pixels, max_pixels=max_pixels + ) + + model_name = "qwen2-vl" + results = [] + + def process_qwen2_vl(img_url, prompt_text): + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€ URL๊ณผ ํ”„๋กฌํ”„ํŠธ๋กœ Qwen2-VL ๋ชจ๋ธ์„ ์ถ”๋ก ํ•˜๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜. + """ + try: + # ๋ฉ”์‹œ์ง€ ๊ตฌ์„ฑ + messages = [ + { + "role": "user", + "content": [ + {"type": "image", "image": img_url}, + {"type": "text", "text": prompt_text}, + ], + } + ] + # ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ ์ ์šฉ + input_text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) + image_inputs, video_inputs = process_vision_info(messages) + + # ๋ชจ๋ธ ์ž…๋ ฅ ์ƒ์„ฑ + inputs = processor( + text=[input_text], + images=image_inputs, + videos=video_inputs, + padding=True, + return_tensors="pt", + ).to("cuda") + + # ๋ชจ๋ธ ์ถ”๋ก  + generated_ids = model.generate(**inputs, max_new_tokens=512) + generated_ids_trimmed = [ + out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids) + ] + output_text = processor.batch_decode( + generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False + ) + return output_text[0] + except Exception as e: + print(f"Error processing image at {img_url}: {e}") + return "Error" + + start_total = time.time() + for idx, (img_url, product_name) in enumerate(zip(image_urls, product_names)): + start_time = time.time() + + # ํ•„์š”ํ•œ ๊ฒฝ์šฐ {product_name} ์น˜ํ™˜ + prompt = base_prompt.replace("{product_name}", product_name) + + output = process_qwen2_vl(img_url, prompt) + elapsed_time = time.time() - start_time + + results.append({ + "Model": model_name, + "ImageURL": img_url, + "Prompt": prompt, + "Inference Time (s)": elapsed_time, + "Model Output": output + }) + + print(f"[Qwen2-VL] {idx+1}/{len(image_urls)} => {elapsed_time:.2f}s => {product_name}") + + total_time = time.time() - start_total + print(f"[Qwen2-VL] Total time: {total_time:.2f}s") + + # ๊ฒฐ๊ณผ CSV ์ €์žฅ + pd.DataFrame(results).to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[Qwen2-VL] Results saved => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/inference_model/unsloth_qwen2_vl.py b/models/thumbnail_description/src/description_pipeline/inference_model/unsloth_qwen2_vl.py new file mode 100644 index 0000000..f945037 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/inference_model/unsloth_qwen2_vl.py @@ -0,0 +1,145 @@ +import os +import time +import re +import yaml +import pandas as pd +import torch +import requests +from PIL import Image +from unsloth import FastVisionModel +from transformers import TextStreamer +from qwen_vl_utils import process_vision_info + +from utils.common_utils import set_seed, load_and_filter_data + +def run_inference_unsloth_qwen2_vl(): + """ + unsloth ๊ธฐ๋ฐ˜ Qwen2-VL ๋ชจ๋ธ ์ถ”๋ก . + config.yaml์„ ํ†ตํ•ด CSV, ํ”„๋กฌํ”„ํŠธ, ๊ฒฐ๊ณผ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด ์‹คํ–‰. + """ + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + csv_name = config["paths"]["cleaned_text_contents"] + out_name = config["paths"]["unsloth_qwen2_eval"] + + # ์‹ค์ œ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + prompt_path = os.path.join(prompt_dir, "unsloth_prompt.txt") + output_csv = os.path.join(data_dir, out_name) + + # 2) ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) CSV ๋กœ๋“œ & ํ•„ํ„ฐ๋ง + df_filtered = load_and_filter_data(csv_path) + image_urls = df_filtered['url_clean'].to_list() + product_names = df_filtered['์ƒํ’ˆ๋ช…'].to_list() + + # 4) ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(prompt_path, "r", encoding="utf-8") as f: + base_prompt = f.read().strip() + + # 5) unsloth ๊ธฐ๋ฐ˜ Qwen2-VL ๋ชจ๋ธ ๋กœ๋”ฉ + print("[unsloth] Loading Qwen2-VL-7B-Instruct model...") + model, tokenizer = FastVisionModel.from_pretrained( + "unsloth/Qwen2-VL-7B-Instruct", + load_in_4bit=False, + use_gradient_checkpointing="True", + trust_remote_code=True, + ) + + # LoRA ์„ค์ • ๋“ฑ + model = FastVisionModel.get_peft_model( + model, + finetune_vision_layers=True, + finetune_language_layers=True, + finetune_attention_modules=True, + finetune_mlp_modules=True, + r=16, + lora_alpha=16, + lora_dropout=0, + bias="none", + random_state=3407, + use_rslora=False, + loftq_config=None + ) + FastVisionModel.for_inference(model) + + # ์ด๋ฏธ์ง€ ํฌ๊ธฐ ์„ค์ • + min_pixels = 256 * 28 * 28 + max_pixels = 960 * 28 * 28 + model_name = "qwen_unsloth" + results = [] + + def process_single_image(img_url, product_name): + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€ URL๊ณผ product_name์œผ๋กœ ๋ชจ๋ธ ์ถ”๋ก  ์‹คํ–‰. + """ + start_time = time.time() + + prompt_text = base_prompt.replace("{product_name}", product_name) + messages = [ + { + "role": "user", + "content": [ + { + "type": "image", + "image": img_url, + "min_pixels": min_pixels, + "max_pixels": max_pixels, + }, + {"type": "text", "text": prompt_text} + ] + } + ] + input_text = tokenizer.apply_chat_template(messages, add_generation_prompt=True) + image_inputs, video_inputs = process_vision_info(messages) + + # ์ž…๋ ฅ ํ…์„œ ์ƒ์„ฑ + inputs = tokenizer( + image_inputs, + input_text, + add_special_tokens=False, + return_tensors="pt", + ).to("cuda") + + # ๋ชจ๋ธ ์ถ”๋ก  + output_ids = model.generate( + **inputs, + max_new_tokens=256, + use_cache=True, + temperature=1.5, + min_p=0.1 + ) + output_texts = tokenizer.batch_decode( + output_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False + ) + + # assistant\n (ํ…์ŠคํŠธ) ์ •๊ทœํ‘œํ˜„์‹์œผ๋กœ ์ถ”์ถœ + pattern = r'assistant\n(.+)' + matches = re.findall(pattern, output_texts[0], re.DOTALL) + final_output = matches[0] if matches else "No valid output generated" + + elapsed = time.time() - start_time + return final_output, elapsed + + # 6) ๊ฐ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์ถ”๋ก  + for idx, (img_url, prod_name) in enumerate(zip(image_urls, product_names)): + caption, elapsed_time = process_single_image(img_url, prod_name) + results.append({ + "Model": model_name, + "ImageURL": img_url, + "Product Name": prod_name, + "Inference Time (s)": elapsed_time, + "Model Output": caption + }) + print(f"[unsloth Qwen2-VL] {idx+1}/{len(image_urls)} => {elapsed_time:.2f}s => {prod_name}") + + # 7) ๊ฒฐ๊ณผ CSV ์ €์žฅ + df = pd.DataFrame(results) + df.to_csv(output_csv, index=False, encoding="utf-8-sig") + print(f"[unsloth Qwen2-VL] Saved results => {output_csv}") \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_hcx_translation.py b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_hcx_translation.py new file mode 100644 index 0000000..64e3ac9 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_hcx_translation.py @@ -0,0 +1,104 @@ +from utils.common_utils import ( + set_seed, requests, pd, time +) +import yaml + +class CompletionExecutor: + def __init__(self, host, api_key, request_id): + self._host = host + self._api_key = api_key + self._request_id = request_id + + def execute(self, completion_request, max_retries=5, retry_delay=20): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id, + 'Content-Type': 'application/json; charset=utf-8', + } + for attempt in range(max_retries): + try: + url = self._host + '/testapp/v1/chat-completions/HCX-003' + response = requests.post(url, headers=headers, json=completion_request) + response_data = response.json() + + if response_data.get("status", {}).get("code") == "20000": + return response_data["result"]["message"]["content"] + else: + raise ValueError(f"Invalid status code: {response_data.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < max_retries - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. {retry_delay}์ดˆ ํ›„ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. (์‹œ๋„ {attempt+1}/{max_retries})") + time.sleep(retry_delay) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ {max_retries}ํšŒ๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None + +def main(): + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config_data = yaml.safe_load(f) + + # HCX API ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + host = config_data["hcx_api"]["host"] + api_key = config_data["hcx_api"]["api_key"] + request_id = config_data["hcx_api"]["request_id"] + + # paths ์„น์…˜์—์„œ ๊ฒฝ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ + data_dir = config_data["paths"]["data_dir"] + hcx_prompt_dir = config_data["paths"].get("hcx_prompt_dir", "hcx_prompt") + csv_name = config_data["paths"].get("qwen2_5+janus_323_eval", "qwen2_5+janus_323_eval.csv") + + # ์‹ค์ œ CSV ๊ฒฝ๋กœ ๊ตฌ์„ฑ + csv_path = os.path.join(data_dir, csv_name) + + # prompt ํŒŒ์ผ ๊ฒฝ๋กœ ๊ตฌ์„ฑ + system_prompt_path = os.path.join(hcx_prompt_dir, "system_janus_pro_hcx_translation.txt") + user_prompt_path = os.path.join(hcx_prompt_dir, "user_janus_pro_hcx_translation.txt") + + completion_executor = CompletionExecutor(host, api_key, request_id) + + # system / user prompt ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(system_prompt_path, "r", encoding="utf-8") as f: + system_prompt = f.read().strip() + + with open(user_prompt_path, "r", encoding="utf-8") as f: + user_prompt_template = f.read().strip() + + # CSV ๋กœ๋“œ + df = pd.read_csv(csv_path) + + # ๊ฐ ํ–‰์— ๋Œ€ํ•ด ์ถ”๋ก  ์‹คํ–‰ + for idx, row in df.iterrows(): + # "Model Output" ์นผ๋Ÿผ์—์„œ ํ…์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ + model_output_text = row.get("Model Output", "") + + # user ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ + user_prompt = user_prompt_template.replace("{model_output_text}", model_output_text) + + request_data = { + 'messages': [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt} + ], + 'topP': 0.9, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.1, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': True, + 'seed': 42 + } + + # HCX ๋ชจ๋ธ ํ˜ธ์ถœ + model_output_ko = completion_executor.execute(request_data) + df.loc[idx, "Model Output HCX"] = model_output_ko + + print(idx, model_output_ko) + + # ๊ฒฐ๊ณผ ์ €์žฅ (๋ฎ์–ด์“ฐ๊ธฐ) + df.to_csv(csv_path, index=False, encoding="utf-8-sig") + print(f"[janus_pro_hcx_translation] ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {csv_path}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_papago_translation.py b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_papago_translation.py new file mode 100644 index 0000000..7c34af9 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_papago_translation.py @@ -0,0 +1,46 @@ +from utils.common_utils import ( + set_seed, requests, pd +) +import yaml + +def translate_text(text, source_lang, target_lang, client_id, client_secret): + url = "https://naveropenapi.apigw.ntruss.com/nmt/v1/translation" + headers = { + "x-ncp-apigw-api-key-id": client_id, + "x-ncp-apigw-api-key": client_secret + } + data = { + "source": source_lang, + "target": target_lang, + "text": text + } + + resp = requests.post(url, headers=headers, data=data) + if resp.status_code == 200: + js = resp.json() + return js['message']['result']['translatedText'] + else: + print(f"Papago Error Code: {resp.status_code}") + return None + +def main(): + # config.yaml์—์„œ Papago API ์ •๋ณด ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + cfg = yaml.safe_load(f) + + client_id = cfg["papago_api"]["client_id"] + client_secret = cfg["papago_api"]["client_secret"] + + csv_path = "qwen2_5+janus_323_eval.csv" + df = pd.read_csv(csv_path) + + # Model Output ์—ด ์˜์–ด๋ฅผ ํ•œ๊ตญ์–ด๋กœ ๋ฒˆ์—ญ + df["Model Output Papago"] = df["Model Output"].apply( + lambda x: translate_text(str(x), "en", "ko", client_id, client_secret) + ) + + df.to_csv(csv_path, index=False, encoding="utf-8-sig") + print(f"[papago_translation] ๋ฒˆ์—ญ ์™„๋ฃŒ => {csv_path}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_pp_hcx.py b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_pp_hcx.py new file mode 100644 index 0000000..fb5d124 --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/post_processing/janus_pro_pp_hcx.py @@ -0,0 +1,106 @@ +from utils.common_utils import ( + set_seed, requests, pd, time +) +import yaml + +class CompletionExecutor: + def __init__(self, host, api_key, request_id): + self._host = host + self._api_key = api_key + self._request_id = request_id + + def execute(self, completion_request, max_retries=5, retry_delay=20): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id, + 'Content-Type': 'application/json; charset=utf-8', + } + for attempt in range(max_retries): + try: + response = requests.post( + self._host + '/testapp/v1/chat-completions/HCX-003', + headers=headers, json=completion_request + ) + data = response.json() + + if data.get("status", {}).get("code") == "20000": + return data["result"]["message"]["content"] + else: + raise ValueError(f"Invalid status code: {data.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < max_retries - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. {retry_delay}์ดˆ ํ›„ ์žฌ์‹œ๋„ (์‹œ๋„ {attempt+1}/{max_retries})") + time.sleep(retry_delay) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ {max_retries}ํšŒ ์ดˆ๊ณผ. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None + +def main(): + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # HCX API ์ •๋ณด + host = config["hcx_api"]["host"] + api_key = config["hcx_api"]["api_key"] + request_id = config["hcx_api"]["request_id"] + + # data_dir & prompt_dir ๋“ฑ ๊ฐ€์ ธ์˜ค๊ธฐ + data_dir = config["paths"]["data_dir"] + prompt_dir = config["paths"]["prompt_dir"] + + # Foodly_323_product_information.csv ๊ฒฝ๋กœ + csv_name = config["paths"]["Foodly_323_product_information"] + csv_path = os.path.join(data_dir, csv_name) + + # system / user ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ ๊ฒฝ๋กœ + system_prompt_path = os.path.join(prompt_dir, "system_janus_pro_hcx_fewshot.txt") + user_prompt_path = os.path.join(prompt_dir, "user_janus_pro_hcx_fewshot.txt") + + completion_executor = CompletionExecutor(host, api_key, request_id) + + # CSV ํŒŒ์ผ ๋กœ๋“œ + df = pd.read_csv(csv_path) + + # system / user prompt ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(system_prompt_path, "r", encoding="utf-8") as sf: + system_prompt_fewshot = sf.read().strip() + + with open(user_prompt_path, "r", encoding="utf-8") as uf: + user_prompt_template_fewshot = uf.read().strip() + + # ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 3) ๊ฐ ํ–‰์— ๋Œ€ํ•ด HCX ๋ชจ๋ธ ํ˜ธ์ถœ + for idx, row in df.iterrows(): + model_output_text = row.get("Janus_Pro_Model_Output", "") + # user ํ”„๋กฌํ”„ํŠธ์— CSV์—์„œ ๊ฐ€์ ธ์˜จ ํ…์ŠคํŠธ๋ฅผ ์น˜ํ™˜ + user_prompt = user_prompt_template_fewshot.replace("{model_output_text}", model_output_text) + + request_data = { + "messages": [ + {"role": "system", "content": system_prompt_fewshot}, + {"role": "user", "content": user_prompt} + ], + 'topP': 0.9, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.1, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': True, + 'seed': 42 + } + + result_ko = completion_executor.execute(request_data) + df.loc[idx, "Janus_Pro_Model_Output_HCX"] = result_ko + + print(idx, result_ko) + + # 4) ๊ฒฐ๊ณผ CSV ์ €์žฅ (๊ฐ™์€ ํŒŒ์ผ์— ๋ฎ์–ด์“ฐ๊ธฐ) + df.to_csv(csv_path, index=False, encoding="utf-8-sig") + print(f"[fewshot_janus_pro_hcx] ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ => {csv_path}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/description_pipeline/post_processing/qwen2_5_pp_hcx.py b/models/thumbnail_description/src/description_pipeline/post_processing/qwen2_5_pp_hcx.py new file mode 100644 index 0000000..53ac0af --- /dev/null +++ b/models/thumbnail_description/src/description_pipeline/post_processing/qwen2_5_pp_hcx.py @@ -0,0 +1,94 @@ +from utils.common_utils import ( + set_seed, requests, pd, time +) +import yaml + +class CompletionExecutor: + def __init__(self, host, api_key, request_id): + self._host = host + self._api_key = api_key + self._request_id = request_id + + def execute(self, completion_request, max_retries=5, retry_delay=20): + headers = { + 'Authorization': self._api_key, + 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id, + 'Content-Type': 'application/json; charset=utf-8' + } + for attempt in range(max_retries): + try: + response = requests.post( + self._host + '/testapp/v1/chat-completions/HCX-003', + headers=headers, json=completion_request + ) + data = response.json() + + if data.get("status", {}).get("code") == "20000": + return data["result"]["message"]["content"] + else: + raise ValueError(f"Invalid status code: {data.get('status', {}).get('code')}") + except (requests.RequestException, ValueError, KeyError) as e: + if attempt < max_retries - 1: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {str(e)}. {retry_delay}์ดˆ ํ›„ ์žฌ์‹œ๋„. (์‹œ๋„ {attempt+1}/{max_retries})") + time.sleep(retry_delay) + else: + print(f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ {max_retries}ํšŒ ์ดˆ๊ณผ. ์ตœ์ข… ์—๋Ÿฌ: {str(e)}") + return None + +def main(): + # 1) config.yaml ๋กœ๋“œ + with open("config/config.yaml", "r", encoding="utf-8") as f: + cfg = yaml.safe_load(f) + + host = cfg["hcx_api"]["host"] + api_key = cfg["hcx_api"]["api_key"] + request_id = cfg["hcx_api"]["request_id"] + + completion_executor = CompletionExecutor(host, api_key, request_id) + + # 2) system / user prompt๋ฅผ ํŒŒ์ผ์—์„œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open("hcx_prompt/system_qwen2_5_pp_hcx.txt", "r", encoding="utf-8") as sf: + system_prompt = sf.read().strip() + + with open("hcx_prompt/user_qwen2_5_pp_hcx.txt", "r", encoding="utf-8") as uf: + user_prompt_template = uf.read().strip() + + # 3) CSV ๋กœ๋“œ + csv_path = "qwen2.5_323_eval.csv" + df = pd.read_csv(csv_path) + + # ์‹œ๋“œ ์„ค์ • + set_seed(42) + + # 4) ๊ฐ ํ–‰๋ณ„๋กœ HCX ์š”์ฒญ + for idx, row in df.iterrows(): + model_output_text = row.get("Model Output", "") + + # user prompt ๊ตฌ์„ฑ + user_prompt = user_prompt_template.replace("{model_output_text}", model_output_text) + + request_data = { + "messages": [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt} + ], + 'topP': 0.9, + 'topK': 0, + 'maxTokens': 1024, + 'temperature': 0.1, + 'repeatPenalty': 5.0, + 'stopBefore': [], + 'includeAiFilters': True, + 'seed': 42 + } + + model_output_HCX_PP = completion_executor.execute(request_data) + df.loc[idx, "Model Output HCX PP"] = model_output_HCX_PP + print(idx, model_output_HCX_PP) + + # 5) CSV ์ €์žฅ + df.to_csv(csv_path, index=False, encoding="utf-8-sig") + print(f"[qwen2_5_pp_hcx] ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ => {csv_path}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/sft_pipeline/detailed_feature_description.py b/models/thumbnail_description/src/sft_pipeline/detailed_feature_description.py new file mode 100644 index 0000000..3b824a9 --- /dev/null +++ b/models/thumbnail_description/src/sft_pipeline/detailed_feature_description.py @@ -0,0 +1,173 @@ +import argparse +import csv +import os +import requests +import json +from io import BytesIO +from PIL import Image +import yaml +import logging +import openai # pip install openai + +def load_config(config_path: str) -> dict: + with open(config_path, "r", encoding="utf-8") as f: + return yaml.safe_load(f) + +def clean_response_text(text: str) -> str: + """ + ์‘๋‹ต ํ…์ŠคํŠธ์—์„œ Markdown ์ฝ”๋“œ ๋ธ”๋ก(๋ฐฑํ‹ฑ)์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. + """ + text = text.strip() + if text.startswith("```"): + lines = text.splitlines() + if lines[-1].strip().startswith("```"): + lines = lines[1:-1] + else: + lines = lines[1:] + text = "\n".join(lines).strip() + return text + +def analyze_image_with_gpt4o(img_url: str, client: object) -> dict: + """ + GPT-4o๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ œํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ๋ถ„์„ํ•˜๊ณ , + texture, shape, color, transparency, design ์ •๋ณด๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. + + ๋ฐ˜ํ™˜ JSON ํ˜•์‹: + { + "texture": "์˜ˆ: plastic", + "shape": "์˜ˆ: rectangular", + "color": "์˜ˆ: primary: red, secondary: black", + "transparency": "Yes or No", + "design": "์ „์ฒด ๋””์ž์ธ์— ๋Œ€ํ•œ ํ•œ์ค„ ์„ค๋ช…" + } + """ + prompt = ( + "Analyze the following product image and extract the details in English. " + "Provide the answer strictly in JSON format with the following keys:\n\n" + "1. texture\n2. shape\n3. color\n4. transparency\n5. design\n\n" + "Return your answer only as a JSON object." + ) + + try: + response = client.ChatCompletion.create( + model="gpt-4o", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + {"type": "image_url", "image_url": {"url": img_url}}, + ], + } + ], + temperature=0.1, + max_tokens=1024, + ) + # ์‘๋‹ต ๋ฉ”์‹œ์ง€์˜ ํ…์ŠคํŠธ ๋‚ด์šฉ ์ ‘๊ทผ + response_text = response.choices[0].message.content + logging.info("DEBUG: Raw response text: %s", response_text) + cleaned_text = clean_response_text(response_text) + logging.info("DEBUG: Cleaned response text: %s", cleaned_text) + if not cleaned_text.strip(): + raise ValueError("Received empty response text from the API.") + result = json.loads(cleaned_text) + except Exception as e: + logging.error("Error during GPT-4o analysis: %s", e) + result = {"texture": "", "shape": "", "color": "", "transparency": "", "design": ""} + return result + +def process_csv(input_csv: str, output_csv: str, client: object, start_row: int = 324): + """ + input_csv ํŒŒ์ผ์˜ ๊ฐ ํ–‰์— ๋Œ€ํ•ด "๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL"์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•˜๊ณ , + GPT-4o๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ œํ’ˆ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•œ ํ›„, output_csv ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. + + ์ถœ๋ ฅ CSV๋Š” ๋‹ค์Œ ์—ด์„ ๋ฐ˜๋“œ์‹œ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค: + "๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL", "texture", "shape", "color", "transparency", "design" + """ + # ์ถœ๋ ฅ CSV๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋ฉด append, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ž‘์„ฑ + if os.path.exists(output_csv): + output_mode = 'a' + write_header = False + else: + output_mode = 'w' + write_header = True + + with open(input_csv, newline='', encoding='utf-8') as infile: + reader = csv.DictReader(infile) + with open(output_csv, output_mode, newline='', encoding='utf-8') as outfile: + fieldnames = ["๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL", "texture", "shape", "color", "transparency", "design"] + writer = csv.DictWriter(outfile, fieldnames=fieldnames) + if write_header: + writer.writeheader() + for i, row in enumerate(reader, start=0): + # start_row ์ด์ „์˜ ํ–‰์€ ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if i < start_row: + continue + + image_url = row.get("๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL", "").strip() + if not image_url: + logging.info("Row %s: Empty image_url; skipping row.", i) + continue + + # ์ด๋ฏธ์ง€ URL์˜ ์ ‘๊ทผ์„ฑ ํ™•์ธ + try: + resp = requests.get(image_url, timeout=10) + resp.raise_for_status() + except Exception as e: + logging.error("Row %s: Failed to access image from %s: %s", i, image_url, e) + continue + + # GPT-4o๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ๋ถ„์„ ์ˆ˜ํ–‰ + analysis = analyze_image_with_gpt4o(image_url, client) + + output_row = { + "๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL": image_url, + "texture": analysis.get("texture", ""), + "shape": analysis.get("shape", ""), + "color": analysis.get("color", ""), + "transparency": analysis.get("transparency", ""), + "design": analysis.get("design", "") + } + writer.writerow(output_row) + logging.info("Row %s: Processed: %s", i, image_url) + +def main(): + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + parser = argparse.ArgumentParser(description="GPT-4o ์ด๋ฏธ์ง€ ๋ถ„์„ ๋ฐ CSV ์ฒ˜๋ฆฌ") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ (๊ธฐ๋ณธ๊ฐ’: config/config.yaml)" + ) + args = parser.parse_args() + + # ์„ค์ • ํŒŒ์ผ ๋กœ๋“œ + config = load_config(args.config) + + # OpenAI API ํ‚ค ์„ค์ • (config.yaml์˜ openai ์„น์…˜ ํ™œ์šฉ) + openai_api_key = config.get("openai", {}).get("api_key", "") + if not openai_api_key: + raise ValueError("OpenAI API key is not provided in config.") + openai.api_key = openai_api_key + + # OpenAI ํด๋ผ์ด์–ธํŠธ (openai ๋ชจ๋“ˆ ์‚ฌ์šฉ) + client = openai + + # CSV ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • (config.yaml์˜ paths ์„น์…˜ ํ™œ์šฉ) + data_dir = config.get("paths", {}).get("data_dir", "./data") + input_csv_filename = config.get("paths", {}).get("thumbnail_1347", "thumbnail_1347.csv") + output_csv_filename = config.get("paths", {}).get("thumbnail_1347_gpt_train", "thumbnail_1347_gpt_train") + input_csv = os.path.join(data_dir, input_csv_filename) + output_csv = os.path.join(data_dir, output_csv_filename) + + logging.info("Input CSV: %s", input_csv) + logging.info("Output CSV: %s", output_csv) + + process_csv(input_csv, output_csv, client) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models/thumbnail_description/src/sft_pipeline/janus_pro_7b_finetuning.py b/models/thumbnail_description/src/sft_pipeline/janus_pro_7b_finetuning.py new file mode 100644 index 0000000..43022c2 --- /dev/null +++ b/models/thumbnail_description/src/sft_pipeline/janus_pro_7b_finetuning.py @@ -0,0 +1,199 @@ +import argparse +import yaml +import os +import urllib.request +import logging +from io import BytesIO +from PIL import Image +import torch +from transformers import ( + AutoTokenizer, + AutoModelForCausalLM, + TrainingArguments, + Trainer, + TrainerCallback +) +from datasets import load_dataset +from dataclasses import dataclass +from typing import Any, Dict +from janus.models import VLChatProcessor, MultiModalityCausalLM +from janus.utils.io import load_pil_images + +# Trainer ์ฝœ๋ฐฑ: GPU ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ +class MoveToCPUTensorCallback(TrainerCallback): + def on_step_end(self, args, state, control, **kwargs): + torch.cuda.empty_cache() + torch.cuda.ipc_collect() + +def main(): + # argparse๋ฅผ ํ†ตํ•ด config ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ž…๋ ฅ๋ฐ›์Œ + parser = argparse.ArgumentParser(description="Janus-Pro 7B ํŒŒ์ธํŠœ๋‹ ์‹คํ–‰") + parser.add_argument( + "--config", + "-c", + default="config/config.yaml", + help="์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ (๊ธฐ๋ณธ๊ฐ’: config/config.yaml)" + ) + args = parser.parse_args() + + # config.yaml ๋กœ๋“œ + with open(args.config, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + + # config.yaml์˜ ๊ฐ’์„ ํ™œ์šฉํ•˜์—ฌ ๋ณ€์ˆ˜ ์„ค์ • + # ๋ชจ๋ธ๋ช…: config์— janus_pro_finetuning ์„น์…˜์ด ์žˆ๋‹ค๋ฉด ์‚ฌ์šฉ, ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ + model_name = config.get("janus_pro_finetuning", {}).get("model_name", "deepseek-ai/Janus-Pro-7B") + + # CSV ํŒŒ์ผ ๊ฒฝ๋กœ: paths > data_dir์™€ thumbnail_1347_gpt_human_labeling_train ๊ฐ’์„ ์กฐํ•ฉ + data_dir = config.get("paths", {}).get("data_dir", "./data") + csv_file = config.get("paths", {}).get("thumbnail_1347_gpt_human_labeling_train", "thumbnail_1347_gpt_human_labeling_train.csv") + csv_path = os.path.join(data_dir, csv_file) + + # ๋ชจ๋ธ ์ €์žฅ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ (config์— ๋ณ„๋„ ์„ค์ •์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ) + output_dir = config.get("paths", {}).get("janus_pro_output_dir", "./janus_pro7b_finetuned") + + logging.info(f"๋ชจ๋ธ๋ช…: {model_name}") + logging.info(f"ํ•™์Šต CSV ํŒŒ์ผ ๊ฒฝ๋กœ: {csv_path}") + logging.info(f"์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + + # 1. ๋ชจ๋ธ ๋ฐ ํ”„๋กœ์„ธ์„œ/ํ† ํฌ๋‚˜์ด์ € ๋กœ๋“œ + # VLChatProcessor๋ฅผ ์‚ฌ์šฉํ•ด ์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ๋ฐ ํ† ํฌ๋‚˜์ด์ € ๋กœ๋“œ + vl_chat_processor: VLChatProcessor = VLChatProcessor.from_pretrained(model_name) + tokenizer = vl_chat_processor.tokenizer + + # ๋ชจ๋ธ ๋กœ๋“œ (์–‘์žํ™” ์—†์ด, FP16 precision ์‚ฌ์šฉ) + model = AutoModelForCausalLM.from_pretrained( + model_name, + device_map="auto", + trust_remote_code=True, + torch_dtype=torch.float16 + ) + + # 2. CSV ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ์…‹ ๋กœ๋“œ + + data_files = {"train": csv_path} + dataset = load_dataset("csv", data_files=data_files) + + # 3. ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์ •์˜ + def preprocess_function(example): + # ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ ๊ตฌ์„ฑ (CSV ํŒŒ์ผ ๋‚ด ์ปฌ๋Ÿผ๋ช…์— ๋งž๊ฒŒ ์ˆ˜์ •) + text_prompt = ( + f"Texture: {example['texture']}. " + f"Shape: {example['shape']}. " + f"Color: {example['color']}. " + f"Transparency: {example['transparency']}. " + f"Design: {example['design']}." + ) + + # ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ + urllib.request.urlretrieve(example["๋Œ€ํ‘œ ์ด๋ฏธ์ง€ URL"], "full_test.jpg") + img = Image.open("full_test.jpg").convert("RGB") + target_size = (224, 224) + img.thumbnail(target_size, Image.Resampling.LANCZOS) + img.save("test.jpg") + + # ๋Œ€ํ™” ํ˜•์‹ ์ž…๋ ฅ ๊ตฌ์„ฑ + conversation = { + "role": "<|User|>", + "content": f"\n{text_prompt}>", + "images": ["test.jpg"] + } + + # PIL ์ด๋ฏธ์ง€ ๋กœ๋“œ + pil_images = load_pil_images([conversation]) + + # VLChatProcessor๋ฅผ ์‚ฌ์šฉํ•ด ์ž…๋ ฅ ๋ณ€ํ™˜ + prepare_inputs = vl_chat_processor( + conversations=[conversation], + images=pil_images, + force_batchify=True + ).to(model.device) + + # ์ž…๋ ฅ ๋”•์…”๋„ˆ๋ฆฌ ๋ณ€ํ™˜: ํ…์„œํ˜• ๋ฐ์ดํ„ฐ๋Š” FP16์œผ๋กœ ๋ณ€ํ™˜ + prepare_inputs_dict = { + k: (v.to(torch.float16) if isinstance(v, torch.Tensor) and v.is_floating_point() else v) + for k, v in vars(prepare_inputs).items() if not k.startswith("_") + } + + # ์ด๋ฏธ์ง€ ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ + inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs_dict) + if not isinstance(inputs_embeds, torch.Tensor): + inputs_embeds = torch.tensor(inputs_embeds) + inputs_embeds = inputs_embeds.to(torch.float16) + + # ๋ผ๋ฒจ ์ƒ์„ฑ: ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ† ํฌ๋‚˜์ด์ €๋กœ ์ธ์ฝ”๋”ฉ + labels = tokenizer( + text_prompt, + padding="max_length", + truncation=True, + max_length=128, + return_tensors="pt" + )["input_ids"].squeeze(0) + + return { + "inputs_embeds": inputs_embeds.squeeze(0), + "labels": labels + } + + # ๋ฐ์ดํ„ฐ์…‹์— ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์ ์šฉ + dataset = dataset.map(preprocess_function, batched=False) + + # 4. ๋ฐ์ดํ„ฐ Collator ์ •์˜ + @dataclass + class DataCollatorForVLChat: + def __call__(self, features: list) -> Dict[str, torch.Tensor]: + inputs_embeds = [] + labels = [] + for f in features: + # inputs_embeds ์ฒ˜๋ฆฌ + if isinstance(f["inputs_embeds"], torch.Tensor): + inputs_embeds.append(f["inputs_embeds"]) + else: + inputs_embeds.append(torch.tensor(f["inputs_embeds"], dtype=torch.float16)) + # labels ์ฒ˜๋ฆฌ + if isinstance(f["labels"], torch.Tensor): + labels.append(f["labels"]) + else: + labels.append(torch.tensor(f["labels"], dtype=torch.long)) + inputs_embeds_batch = torch.stack(inputs_embeds) + labels_batch = torch.stack(labels) + return { + "inputs_embeds": inputs_embeds_batch, + "labels": labels_batch + } + + data_collator = DataCollatorForVLChat() + + # 5. TrainingArguments ์„ค์ • + training_args = TrainingArguments( + output_dir=output_dir, + num_train_epochs=1, + per_device_train_batch_size=1, + learning_rate=5e-5, + save_steps=80, + fp16=True, + logging_steps=100, + save_total_limit=1, + gradient_accumulation_steps=4, + remove_unused_columns=False + ) + + # 6. Trainer ์ƒ์„ฑ ๋ฐ ํ•™์Šต + trainer = Trainer( + model=model, + args=training_args, + train_dataset=dataset["train"], + tokenizer=tokenizer, + data_collator=data_collator, + callbacks=[MoveToCPUTensorCallback()] + ) + + trainer.train() + trainer.save_model(training_args.output_dir) + +if __name__ == "__main__": + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" + ) + main() \ No newline at end of file diff --git a/models/thumbnail_description/utils/__init__.py b/models/thumbnail_description/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/thumbnail_description/utils/common_utils.py b/models/thumbnail_description/utils/common_utils.py new file mode 100644 index 0000000..41eb602 --- /dev/null +++ b/models/thumbnail_description/utils/common_utils.py @@ -0,0 +1,64 @@ +# utils/common_utils.py + +import os +import random +import numpy as np +import torch +import pandas as pd + +def set_seed(seed: int = 42) -> None: + """ + ๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”Œ๋žซํผ์—์„œ ์žฌํ˜„์„ฑ์„ ์œ„ํ•œ ์‹œ๋“œ ์„ค์ • ํ•จ์ˆ˜. + """ + os.environ["PYTHONHASHSEED"] = str(seed) + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + +def get_second_to_last(df: pd.DataFrame) -> pd.DataFrame: + """ + ๊ฐ ๊ทธ๋ฃน ๋‚ด์—์„œ 'img-ID'๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•œ ํ›„, + ๊ฐ ๊ทธ๋ฃน์˜ ๋’ค์—์„œ ๋‘ ๋ฒˆ์งธ ํ–‰๋งŒ ์ถ”์ถœํ•ด ๋ฐ˜ํ™˜. + """ + df = df.sort_values( + by='img-ID', + key=lambda s: s.str.split('-').str[-1].astype(int), + ascending=True + ) + return df.iloc[0] + + +def load_and_filter_data(csv_path: str) -> pd.DataFrame: + """ + 1. CSV ๋กœ๋“œ + 2. ID๋ณ„ '์ „์ฒด' ํ–‰ ์ •๋ณด๋ฅผ '๊ฐœ๋ณ„' ํ–‰์— ์ฑ„์›Œ๋„ฃ๊ธฐ + 3. ID๋ณ„ ๋’ค์—์„œ ๋‘ ๋ฒˆ์งธ ํ–‰๋งŒ ์ถ”์ถœ + 4. '?ref=storefarm' ์ œ๊ฑฐ + 5. ์ •๋ ฌ ํ›„ ๋ฐ˜ํ™˜ + """ + # 1) CSV ๋กœ๋“œ + df_raw = pd.read_csv(csv_path) + df = df_raw.copy() + + # 2) '์ „์ฒด' ๋ฐ์ดํ„ฐ ์ถ”์ถœ ํ›„, '๊ฐœ๋ณ„'์— ์ •๋ณด ์ฑ„์›Œ๋„ฃ๊ธฐ + df_total = df[df['์ „์ฒด/๊ฐœ๋ณ„'] == '์ „์ฒด'].copy() + fill_cols = ['row', 'img-ID', '์นดํ…Œ๊ณ ๋ฆฌ', '์ƒํ’ˆ๋ช…', '์ƒํ’ˆ ์ƒ์„ธ URL'] + info_dict = df_total.set_index('ID')[fill_cols].to_dict('index') + for col in fill_cols: + df[col] = df['ID'].map(lambda x: info_dict[x][col] if x in info_dict else None) + + # 3) ๊ทธ๋ฃน๋ณ„ ๋’ค์—์„œ ๋‘ ๋ฒˆ์งธ ํ–‰ ์ถ”์ถœ + df_filtered = df.groupby('ID', group_keys=False).apply(get_second_to_last).reset_index(drop=True) + + # 4) ์ด๋ฏธ์ง€ URL์—์„œ '?ref=storefarm' ์ œ๊ฑฐ + df_filtered['url_clean'] = df_filtered['์ด๋ฏธ์ง€ URL'].str.replace('?ref=storefarm', '', regex=False) + + # 5) row ๊ธฐ์ค€ ์ •๋ ฌ + df_filtered = df_filtered.sort_values(by="row").reset_index(drop=True) + + return df_filtered \ No newline at end of file