From d90f1f30b2f214ee490b255731cc81894309fd02 Mon Sep 17 00:00:00 2001 From: Vladlav064 Date: Thu, 12 Nov 2026 08:43:34 +0300 Subject: [PATCH] =?UTF-8?q?=D0=AD=D1=82=D0=B0=D0=BF:=20SQLite=20=D0=B8=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20=D0=BF=D0=B0=D0=B9=D0=BF?= =?UTF-8?q?=D0=BB=D0=B0=D0=B9=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ai_work_log.md | 32 + docs/implementation_plan.md | 14 +- main.py | 32 + outputs/clean_orders.csv | 1483 +++++++++++++++++++++++++++++++ outputs/orders.db | Bin 0 -> 102400 bytes outputs/quality_report.json | 39 + outputs/rejected_rows.csv | 19 + sql/schema.sql | 25 + src/database.py | 33 + src/generate_data.py | 6 +- src/quality.py | 87 ++ tests/test_extract_transform.py | 60 ++ tests/test_generate_data.py | 35 + tests/test_pipeline.py | 130 +++ tests/test_quality.py | 80 ++ 15 files changed, 2069 insertions(+), 6 deletions(-) create mode 100644 main.py create mode 100644 outputs/clean_orders.csv create mode 100644 outputs/orders.db create mode 100644 outputs/quality_report.json create mode 100644 outputs/rejected_rows.csv create mode 100644 sql/schema.sql create mode 100644 src/database.py create mode 100644 src/quality.py create mode 100644 tests/test_pipeline.py create mode 100644 tests/test_quality.py diff --git a/docs/ai_work_log.md b/docs/ai_work_log.md index 201ba1f..06f6f4b 100644 --- a/docs/ai_work_log.md +++ b/docs/ai_work_log.md @@ -35,3 +35,35 @@ **Решения и изменения.** csv.reader в строгом режиме читает UTF-8 с поддержкой BOM и нумерует логические записи после заголовка. Нечитаемый файл, ошибка разбора CSV или неверный заголовок прерывают обработку. Для читаемой записи неверной ширины сохраняются все исходные поля. Точный дубль получает только причину повтора. Для остальных структурно корректных записей собираются ошибки независимых полей. Выручка проверяется при пригодных для расчёта цене и количестве. Среди валидных заказов сначала определяется наличие конфликта во всей группе ID. Номер источника сохраняется и у принятого заказа, но исключён из сравнения нормализованных значений. План обновлён согласно уточнению о нескольких причинах. **Фактические проверки.** Полный запуск pytest дал 32 passed. На синтетическом raw_orders.csv обработаны 1500 записей, приняты 1482, отброшены 18. Из них 14 имели ошибки значений, одна оказалась точным дублем, одна — нормализованным, две отклонены из-за конфликта ID. Проверено, что номера от 1 до 1500 встречаются в совокупном результате ровно по одному разу. Байты CSV до и после обработки совпали, SHA-256 — `c4b9ffd2eb24c6c79b6a3e2436f3bd348ba86696a1aeb9b7e3083af65c799c67`. + +## 12 ноября 2026 — дополнительные проверки генерации, чтения и очистки + +**Запрос пользователя.** Проверить запланированные примеры в CSV, обработку ошибок файла, нумерацию, деньги и приоритет причин отбраковки. Устранить повтор схемы CSV и уточнить план экспорта и аналитики. + +**Изменения.** Генератор использует FIELDS из extract.py. Добавлено шесть тестов. Они проверяют содержимое созданного во временной папке CSV, неверную кодировку, отказ при открытии файла (подмена PermissionError), многострочное поле с CRLF и нумерацию после него, смешанную группу дублей и конфликтов с проверкой порядка обоих списков, расчёт большой суммы с точностью до копейки. Новые проверки прошли на существующей логике очистки. + +**План.** Уточнены состав clean_orders.csv и учёт нескольких причин у одной отброшенной записи. Для будущих отчётов принят календарь между крайними датами принятых заказов. Для аномалий каждой категории учитываются нулевые дни, используется стандартное отклонение генеральной совокупности и строгий двусторонний порог 2σ. При периоде короче семи дней или нулевой дисперсии результат пуст. + +**Проверки.** Через существующую .venv выполнен полный pytest до изменений (32 passed) и после (38 passed). На исходном CSV принято 1482 заказа, отклонено 18. SHA-256 перед работой и после проверок совпал — `c4b9ffd2eb24c6c79b6a3e2436f3bd348ba86696a1aeb9b7e3083af65c799c67`. Повторно сгенерированный во временной папке CSV побайтово совпал с исходным. + +## 12 ноября 2026 — уточнение аналитики и пути экспорта + +По запросу пользователя в плане закреплён путь `outputs/clean_orders.csv` относительно корня проекта. Динамику показываем по общей дневной выручке всех категорий, одной строкой на дату. Аномалии ищем отдельно по дневной выручке каждой категории, используя её собственные среднее и стандартное отклонение. + +## 12 ноября 2026 — статистика и экспорт результатов + +**Запрос пользователя.** Создать quality.py, выгрузить два CSV в UTF-8 с BOM и отчёт JSON, проверить баланс, повторный запуск и пустой снимок. Предусмотреть сохранение после успешной загрузки БД. + +**Решения.** Модуль принимает результаты очистки и отдельное число исходных записей. Проверяет сумму статусов и покрытие всех исходных номеров без повторов. Итоговая причина — первая из обнаруженных в порядке проверок. Отдельные счётчики проблем включают все обнаруженные причины и могут пересекаться. В CSV отбраковки заголовок источника, исходные значения и причины представлены JSON-массивами. Так сохраняются порядок колонок, пустые и лишние поля. Состав чистого CSV уточнён в плане до шести запрошенных колонок. При сборке пайплайна save_outputs будет вызываться после успешного завершения транзакции БД. + +**Фактические проверки.** Через существующую .venv выполнен полный pytest — 40 passed. Временный пример проверил несколько причин у одной записи, порядок, кодировку, обратное чтение значений, побайтовое совпадение при повторном экспорте и замену снимка пустым с долей null. Проверено отклонение несогласованных количеств и повторяющихся номеров. Для текущего этапа три файла созданы прямым вызовом экспорта после очистки. Чтение результатов из outputs подтвердило 1482 принятых и 18 отброшенных из 1500, доля 0,988. Суммы обоих счётчиков на этом наборе равны 18. SHA-256 исходного CSV до и после совпал. + +## 12 ноября 2026 — транзакционная загрузка и запуск пайплайна + +**Запрос пользователя.** Реализовать схему SQLite, полную загрузку заказов и дневных агрегатов и команду python main.py. Проверить повторяемость данных, согласованность CSV, обработку пустого снимка и сохранность предыдущих данных при сбое. + +**Решения.** В sql/schema.sql заданы первичные ключи и ограничения значений. src/database.py открывает одну транзакцию до создания и очистки таблиц, вставляет заказы с параметрами, строит daily_category_revenue одним группирующим запросом и фиксирует обе таблицы вместе. main.py проверяет статистику до записи базы. После фиксации он передаёт готовый отчёт в save_reports. Если экспорт завершается ошибкой, CLI указывает, что база уже обновлена, и сохраняет исходную диагностику. Ранее использовавшийся интерфейс save_outputs сохранён. + +**Фактические проверки.** В существующей .venv прошли все 45 тестов. Пять новых интеграционных тестов запускали копию проекта во временном каталоге из другой рабочей папки. Переполнение суммы группы откатило изменения обеих таблиц. Испорченный CSV сохранил прежний снимок. Набор без принятых заказов очистил обе таблицы. Сбой экспорта после фиксации базы завершил CLI с ненулевым кодом и сообщением об обновлённой БД. + +На рабочем синтетическом CSV команда python main.py создала outputs/orders.db. Вход — 1500 записей, приняты 1482, отброшены 18. Получено 438 групп по дате и категории. Суммарная выручка в обеих таблицах составила 1 687 705 899 копеек. Содержимое обеих таблиц сравнили до и после повторного запуска, заказы сверили по всем шести полям с clean_orders.csv. SHA-256 исходного CSV совпал с исходным замером. Аналитические запросы остаются следующим этапом. diff --git a/docs/implementation_plan.md b/docs/implementation_plan.md index 8b9ef7f..1a9a7b0 100644 --- a/docs/implementation_plan.md +++ b/docs/implementation_plan.md @@ -21,6 +21,7 @@ 3. Проверить число полей. Для записи правильной ширины собрать все ошибки независимых полей в порядке таблицы. Проверить произведение, только если количество и цена прошли проверку. Сохранять один итоговый статус и список фактически установленных причин на запись. 4. Сгруппировать только валидные записи по нормализованному ID. Сравнивать дату, категорию, количество и цену в копейках. Если значения совпадают у всей группы, принять запись с наименьшим номером, остальные отметить как нормализованные дубли. Если есть хотя бы два варианта значений, отклонить всю валидную группу как конфликт ID, включая повторившиеся варианты. Уже отброшенные точные дубли сохраняют исходную причину. 5. Вывести количество прочитанных, принятых и отброшенных записей, разбивку по причинам и номера отклонённых записей. Число прочитанных должно равняться сумме принятых и отброшенных. Сумма счётчиков причин может быть больше числа отброшенных записей. +6. Перед загрузкой БД сформировать статистику через `build_report`, передав число прочитанных записей. После фиксации транзакции вызвать `save_reports(accepted, rejected, report)`. В `outputs/clean_orders.csv` записать колонки `order_id`, `order_date`, `category`, `quantity`, `unit_price_kopecks`, `revenue_kopecks` в исходном порядке записей. В `outputs/rejected_rows.csv` сохранить номер записи, исходный заголовок, значения и причины. В `outputs/quality_report.json` сохранить статистику. Каждый запуск заменяет файлы, пустые CSV содержат заголовки. ## Модули и загрузка @@ -28,24 +29,27 @@ |---|---| | `src/extract.py` | `read_records(path) -> Iterator[RawRecord]`. Передаёт номер записи и исходные значения, проверяет заголовок и ширину записи. | | `src/transform.py` | `clean_orders(records) -> tuple[list[Order], list[RejectedRecord]]`. Рассчитывает выручку одного заказа и возвращает принятые заказы и отбраковку с причинами. | -| `src/storage.py` | `reload_database(path, orders) -> None`. Обновляет обе таблицы атомарно и рассчитывает дневные агрегаты в SQLite. | +| `src/database.py` | `reload_database(path, orders) -> None`. Обновляет обе таблицы атомарно и рассчитывает дневные агрегаты в SQLite. | | `main.py` | Определяет корень по расположению самого файла, собирает пути к ресурсам, вызывает этапы и выводит отчёт. | -В `orders` хранить одну принятую запись на `order_id` (первичный ключ), включая номер записи, дату, категорию, количество, цену и выручку в копейках. В `daily_revenue` хранить сумму выручки в копейках с составным первичным ключом из даты и категории. +В `orders` хранить одну принятую запись на `order_id` (первичный ключ), включая дату, категорию, количество, цену и выручку в копейках. В `daily_category_revenue` хранить количество заказов и сумму выручки в копейках с составным первичным ключом из даты и категории. -В одной явной транзакции создать таблицы при первом запуске, очистить обе, загрузить принятые заказы и заполнить `daily_revenue` запросом с `SUM` и `GROUP BY order_date, category` из `orders`. Это единственное место построения дневной витрины. Зафиксировать транзакцию после успешного завершения всех операций. Ошибка загрузки или переполнение суммы группы отменяет транзакцию целиком, сохраняя предыдущие данные. +В одной явной транзакции создать таблицы при первом запуске, очистить обе, загрузить принятые заказы и заполнить `daily_category_revenue` запросом с `SUM` и `GROUP BY order_date, category` из `orders`. Это единственное место построения дневной витрины. Зафиксировать транзакцию после успешного завершения всех операций. Ошибка загрузки или переполнение суммы группы отменяет транзакцию целиком, сохраняя предыдущие данные. ## Неоднозначности и рабочие допущения -- Исходного CSV пока нет. Предлагаемый формат — UTF-8 с поддержкой BOM, запятая между полями, двойные кавычки для значений с запятой или переводом строки. Для синтетического набора явно указать происхождение в README. Исходный файл открывать только на чтение. +- Исходный синтетический набор находится в `data/raw_orders.csv`. Формат — UTF-8 с поддержкой BOM при чтении, запятая между полями, двойные кавычки для значений с запятой или переводом строки. Указать происхождение в README. При обработке исходный файл открывать только на чтение. - Колонки сопоставлять по именам. Отсутствующее, повторное или лишнее имя в заголовке считать ошибкой файла. Неверное число полей в читаемой записи считать ошибкой записи. Если из-за повреждения CSV границы записей определить невозможно, остановить запуск до загрузки. - Файл с корректным заголовком и нулём принятых заказов считать пустым снимком. При полной перезагрузке обе таблицы станут пустыми. -- Для аналитики предлагаются три запроса к витрине. Топ — пять категорий по суммарной выручке с сортировкой по имени при равенстве. Динамика — сумма по дате и изменение в копейках к предыдущей доступной дате. Аномалия — дневная выручка категории более чем вдвое выше предыдущего наблюдения той же категории. Первое наблюдение пропускается, пропущенные даты нулями не заполняются. Порог — рабочее допущение для тестового задания. +- Для аналитики использовать календарь от первой до последней даты принятого заказа включительно. В отчётах заполнять нулями дни без продаж, в том числе для каждой категории, встречающейся в снимке. Для пустого снимка календарь пуст. +- Топ — пять категорий по суммарной выручке с сортировкой по имени при равенстве. Для динамики суммировать выручку всех категорий за каждый календарный день. Выводить одну строку на дату с общей выручкой и её изменением в копейках к предыдущему дню. Для первого дня изменение не определено. +- Аномалии искать отдельно для каждой категории. По всему календарю, включая нулевые дни, по дневной выручке этой категории рассчитать среднее и стандартное отклонение генеральной совокупности (дисперсия с делением на число дней). Отмечать день при абсолютном отклонении от среднего строго больше двух стандартных отклонений. Проверять как рост, так и падение. При числе дней меньше 7 или нулевой дисперсии аномалии не выдавать. ## Критерии готовности реализации - На pytest проверить оба формата дат, невозможные даты, пробелы, пустые поля, дробное количество, варианты цены и переполнение на границе INTEGER. Проверить нумерацию на CSV с многострочным полем. - На размеченном примере сверить статус каждой исходной записи, причины и баланс счётчиков. Включить повтор невалидной записи, одинаковые нормализованные заказы, конфликт из трёх записей с двумя совпадающими вариантами и валидную запись рядом с невалидной того же ID. - Сверить копейки по известному примеру. Две единицы по 10,25 рубля и одна за 0,50 рубля в тот же день и в той же категории должны дать одну строку витрины на 2100 копеек. +- Сверить строки `outputs/clean_orders.csv` с принятыми заказами. Для аналитики проверить календарный пропуск, периоды в 6 и 7 дней, постоянную выручку и значения ниже, выше и точно на границе двух стандартных отклонений. - Запустить пайплайн дважды с тем же CSV, в том числе из другой рабочей папки. Сравнить содержимое обеих таблиц, отчёты и контрольную сумму исходного файла. На изменённом снимке проверить удаление устаревших заказов и агрегатов. На переполнении суммы группы проверить откат обеих таблиц. - Перед сдачей подготовить готовую SQLite-базу, три SQL-запроса с фактическими результатами, README с командами запуска и тестов и журнал фактически выполненных проверок. diff --git a/main.py b/main.py new file mode 100644 index 0000000..10744aa --- /dev/null +++ b/main.py @@ -0,0 +1,32 @@ +import sqlite3 +import sys + +from src.database import reload_database +from src.extract import CSVFileError, read_records +from src.quality import OUTPUT_DIR, build_report, save_reports +from src.transform import clean_orders + + +def main() -> int: + try: + records = list(read_records()) + accepted, rejected = clean_orders(records) + report = build_report(accepted, rejected, len(records)) + reload_database(OUTPUT_DIR / "orders.db", accepted) + except (CSVFileError, sqlite3.Error, OSError) as exc: + print(f"Загрузка не завершена. {type(exc).__name__}: {exc}", file=sys.stderr) + return 1 + + try: + save_reports(accepted, rejected, report) + except Exception as exc: + exc.add_note("База уже обновлена. Сохранение файлов отчётов не завершено.") + raise + + print(f"Загрузка и экспорт завершены. Прочитано {len(records)}, " + f"принято {len(accepted)}, отброшено {len(rejected)}.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/outputs/clean_orders.csv b/outputs/clean_orders.csv new file mode 100644 index 0000000..a749dda --- /dev/null +++ b/outputs/clean_orders.csv @@ -0,0 +1,1483 @@ +order_id,order_date,category,quantity,unit_price_kopecks,revenue_kopecks +718,2024-01-30,Электроника,8,110844,886752 +1300,2024-01-03,Книги,3,127754,383262 +883,2024-02-09,Спорт,4,366308,1465232 +1270,2024-01-03,Электроника,1,445429,445429 +97,2024-01-01,Товары для дома,5,174880,874400 +682,2024-03-02,Одежда,5,109519,547595 +1290,2024-02-18,Товары для дома,7,475657,3329599 +1006,2024-02-24,Одежда,8,45943,367544 +1353,2024-03-11,Электроника,6,149157,894942 +1235,2024-02-22,Спорт,7,203441,1424087 +598,2024-03-12,Одежда,3,364995,1094985 +403,2024-02-20,Одежда,6,456406,2738436 +1101,2024-01-03,Книги,4,354811,1419244 +481,2024-02-28,Одежда,4,19391,77564 +1267,2024-03-23,Книги,5,318048,1590240 +1032,2024-03-13,Электроника,2,308247,616494 +1341,2024-01-19,Электроника,7,247291,1731037 +699,2024-03-08,Книги,1,17734,17734 +1224,2024-03-06,Электроника,8,420908,3367264 +169,2024-02-23,Книги,8,132263,1058104 +934,2024-02-03,Товары для дома,1,429964,429964 +1362,2024-03-28,Электроника,1,241551,241551 +53,2024-01-01,Книги,4,37221,148884 +1158,2024-02-27,Книги,8,165708,1325664 +1196,2024-01-14,Электроника,4,323019,1292076 +1407,2024-02-27,Книги,7,466424,3264968 +1388,2024-02-04,Электроника,6,247121,1482726 +286,2024-01-22,Одежда,1,363857,363857 +260,2024-01-15,Книги,3,241932,725796 +398,2024-01-15,Книги,6,212354,1274124 +871,2024-03-08,Книги,6,465948,2795688 +66,2024-03-11,Книги,1,51333,51333 +362,2024-01-12,Книги,2,436089,872178 +798,2024-02-10,Товары для дома,5,61794,308970 +999,2024-03-31,Спорт,3,16250,48750 +387,2024-03-08,Одежда,1,349770,349770 +1361,2024-02-01,Одежда,8,397135,3177080 +179,2024-01-26,Электроника,4,39845,159380 +997,2024-02-18,Книги,2,84361,168722 +1231,2024-03-28,Книги,8,80612,644896 +470,2024-01-19,Спорт,1,152711,152711 +931,2024-01-28,Одежда,3,438266,1314798 +444,2024-03-27,Товары для дома,8,377271,3018168 +209,2024-01-13,Товары для дома,5,436538,2182690 +366,2024-03-26,Спорт,1,493424,493424 +1438,2024-01-25,Электроника,7,215869,1511083 +1046,2024-01-08,Товары для дома,2,270150,540300 +745,2024-01-22,Одежда,5,72793,363965 +1251,2024-01-21,Товары для дома,5,96466,482330 +750,2024-03-17,Товары для дома,8,323313,2586504 +225,2024-03-19,Книги,4,388020,1552080 +330,2024-01-13,Одежда,6,359494,2156964 +1266,2024-03-03,Книги,3,289235,867705 +658,2024-01-25,Книги,1,491474,491474 +1188,2024-02-15,Спорт,7,294797,2063579 +454,2024-02-27,Электроника,3,474642,1423926 +301,2024-03-25,Одежда,1,207517,207517 +489,2024-02-13,Спорт,8,97947,783576 +1492,2024-01-14,Товары для дома,2,254474,508948 +372,2024-02-24,Электроника,1,443105,443105 +276,2024-01-13,Спорт,2,458328,916656 +1444,2024-01-18,Книги,8,151832,1214656 +972,2024-01-17,Товары для дома,6,178656,1071936 +1414,2024-02-04,Спорт,6,465407,2792442 +967,2024-03-13,Товары для дома,8,497219,3977752 +383,2024-03-25,Спорт,8,222306,1778448 +1023,2024-01-16,Спорт,3,497683,1493049 +1100,2024-01-02,Одежда,4,467669,1870676 +2,2024-02-01,Товары для дома,2,117027,234054 +1187,2024-03-05,Одежда,2,284422,568844 +235,2024-01-10,Товары для дома,5,31268,156340 +508,2024-03-24,Товары для дома,2,146114,292228 +191,2024-02-29,Электроника,7,298766,2091362 +91,2024-03-25,Товары для дома,5,54310,271550 +1313,2024-01-03,Электроника,7,106089,742623 +1387,2024-01-24,Одежда,4,287606,1150424 +802,2024-03-03,Электроника,3,333186,999558 +1131,2024-02-07,Одежда,7,188857,1321999 +1427,2024-03-11,Товары для дома,3,233227,699681 +422,2024-01-11,Товары для дома,1,264529,264529 +459,2024-01-29,Одежда,2,14779,29558 +432,2024-03-17,Книги,5,371634,1858170 +255,2024-01-07,Одежда,3,106724,320172 +167,2024-02-18,Товары для дома,8,171628,1373024 +98,2024-01-21,Спорт,7,388619,2720333 +741,2024-03-11,Электроника,6,48793,292758 +410,2024-03-13,Электроника,8,398395,3187160 +23,2024-01-05,Одежда,7,422076,2954532 +405,2024-03-06,Книги,4,331993,1327972 +1103,2024-01-17,Спорт,5,53849,269245 +220,2024-01-11,Книги,7,130124,910868 +227,2024-01-21,Товары для дома,2,125759,251518 +309,2024-02-23,Товары для дома,3,92086,276258 +857,2024-03-23,Товары для дома,2,355015,710030 +258,2024-03-31,Одежда,1,83036,83036 +774,2024-03-27,Электроника,3,308591,925773 +861,2024-01-12,Книги,3,470073,1410219 +42,2024-01-15,Одежда,5,487116,2435580 +613,2024-02-12,Спорт,8,149193,1193544 +517,2024-02-08,Товары для дома,3,446359,1339077 +287,2024-01-06,Книги,5,170066,850330 +1400,2024-01-28,Одежда,8,426676,3413408 +696,2024-01-22,Одежда,3,384184,1152552 +764,2024-01-31,Товары для дома,7,132478,927346 +909,2024-02-29,Электроника,8,193082,1544656 +849,2024-02-24,Книги,2,343664,687328 +1274,2024-02-20,Электроника,5,117077,585385 +401,2024-02-25,Книги,4,442754,1771016 +335,2024-01-17,Электроника,4,412604,1650416 +1209,2024-01-06,Одежда,1,80585,80585 +701,2024-01-09,Товары для дома,1,370761,370761 +417,2024-02-06,Книги,7,40230,281610 +413,2024-01-09,Спорт,5,245850,1229250 +1203,2024-01-25,Спорт,3,154234,462702 +1156,2024-01-31,Спорт,8,41330,330640 +1206,2024-02-24,Электроника,5,146336,731680 +76,2024-01-08,Книги,3,266249,798747 +107,2024-01-21,Товары для дома,7,419372,2935604 +1280,2024-03-02,Одежда,1,492399,492399 +157,2024-03-14,Спорт,1,199430,199430 +59,2024-01-13,Спорт,6,50820,304920 +430,2024-02-12,Электроника,3,42731,128193 +102,2024-02-25,Книги,5,66819,334095 +968,2024-03-10,Товары для дома,8,162033,1296264 +407,2024-01-14,Одежда,4,76779,307116 +154,2024-02-23,Одежда,8,213700,1709600 +485,2024-03-23,Одежда,6,100194,601164 +969,2024-01-05,Книги,4,47321,189284 +1016,2024-03-30,Книги,2,349946,699892 +984,2024-03-04,Одежда,2,73738,147476 +1009,2024-03-01,Книги,5,442379,2211895 +1202,2024-03-22,Одежда,4,369429,1477716 +431,2024-02-14,Спорт,3,162651,487953 +575,2024-01-03,Одежда,2,193126,386252 +315,2024-01-02,Электроника,2,138653,277306 +832,2024-02-21,Одежда,6,270330,1621980 +673,2024-02-08,Товары для дома,8,197374,1578992 +614,2024-01-18,Электроника,8,446201,3569608 +636,2024-01-08,Электроника,4,434517,1738068 +1289,2024-03-16,Книги,5,342537,1712685 +1005,2024-01-20,Одежда,1,28577,28577 +952,2024-01-26,Электроника,4,336936,1347744 +386,2024-03-27,Электроника,8,355723,2845784 +1043,2024-02-11,Спорт,2,141254,282508 +1396,2024-01-02,Спорт,8,92594,740752 +1357,2024-02-22,Книги,2,265415,530830 +1436,2024-02-08,Спорт,5,4789,23945 +1319,2024-02-17,Книги,7,458660,3210620 +995,2024-02-07,Одежда,5,10527,52635 +421,2024-01-08,Книги,6,236204,1417224 +516,2024-03-31,Электроника,5,34047,170235 +980,2024-02-18,Одежда,3,160864,482592 +894,2024-01-08,Электроника,3,261940,785820 +388,2024-01-29,Электроника,1,207232,207232 +1212,2024-03-31,Электроника,4,166650,666600 +733,2024-02-01,Книги,2,373875,747750 +210,2024-01-30,Товары для дома,5,189206,946030 +1052,2024-02-17,Спорт,7,431755,3022285 +544,2024-01-27,Электроника,3,178359,535077 +763,2024-03-27,Товары для дома,5,261779,1308895 +293,2024-03-22,Спорт,5,133158,665790 +991,2024-01-22,Спорт,8,463760,3710080 +395,2024-01-03,Книги,6,241044,1446264 +1155,2024-03-11,Спорт,7,337284,2360988 +1261,2024-02-24,Книги,6,88416,530496 +867,2024-03-07,Электроника,4,318205,1272820 +905,2024-02-21,Спорт,5,36138,180690 +679,2024-02-17,Электроника,4,48478,193912 +174,2024-01-17,Книги,4,248283,993132 +1291,2024-02-15,Одежда,8,428468,3427744 +1098,2024-02-24,Спорт,1,250296,250296 +433,2024-03-12,Одежда,3,197489,592467 +1406,2024-02-06,Одежда,8,186180,1489440 +253,2024-02-22,Товары для дома,6,28419,170514 +842,2024-01-16,Товары для дома,8,487291,3898328 +1378,2024-03-03,Электроника,5,95878,479390 +49,2024-02-09,Одежда,8,209187,1673496 +441,2024-03-17,Товары для дома,3,197510,592530 +958,2024-03-17,Книги,5,114830,574150 +11,2024-01-13,Товары для дома,5,188209,941045 +1199,2024-02-18,Спорт,6,203191,1219146 +518,2024-02-16,Товары для дома,2,266735,533470 +681,2024-01-10,Электроника,4,98652,394608 +649,2024-03-23,Спорт,6,382358,2294148 +346,2024-03-06,Книги,8,311252,2490016 +595,2024-02-07,Одежда,2,22055,44110 +21,2024-02-29,Одежда,4,198944,795776 +88,2024-02-26,Электроника,5,437123,2185615 +957,2024-02-04,Книги,6,94276,565656 +94,2024-02-13,Одежда,8,106744,853952 +785,2024-01-30,Спорт,3,418254,1254762 +1191,2024-01-04,Товары для дома,1,199686,199686 +1459,2024-02-28,Книги,4,385521,1542084 +445,2024-03-19,Спорт,4,149385,597540 +919,2024-03-22,Спорт,2,429897,859794 +1173,2024-01-14,Спорт,1,396965,396965 +988,2024-02-01,Книги,6,363424,2180544 +981,2024-01-23,Книги,7,382118,2674826 +1278,2024-03-06,Спорт,3,73595,220785 +559,2024-02-25,Одежда,6,70221,421326 +450,2024-01-26,Электроника,3,420091,1260273 +321,2024-03-30,Спорт,2,158435,316870 +606,2024-03-24,Одежда,6,104573,627438 +364,2024-03-12,Электроника,6,31448,188688 +813,2024-03-14,Одежда,6,59878,359268 +824,2024-03-31,Одежда,5,153425,767125 +1434,2024-02-14,Спорт,1,150347,150347 +1049,2024-01-23,Товары для дома,1,101064,101064 +572,2024-01-21,Электроника,5,206022,1030110 +262,2024-02-23,Спорт,8,437636,3501088 +1485,2024-03-20,Одежда,2,125193,250386 +672,2024-03-30,Спорт,3,218275,654825 +800,2024-03-06,Спорт,3,203667,611001 +1349,2024-01-31,Книги,3,343419,1030257 +1096,2024-03-03,Книги,3,411677,1235031 +123,2024-02-02,Спорт,1,23272,23272 +515,2024-03-28,Одежда,6,443297,2659782 +720,2024-03-10,Книги,3,295442,886326 +1024,2024-01-22,Товары для дома,3,111092,333276 +697,2024-01-18,Электроника,8,377652,3021216 +933,2024-02-20,Книги,5,269201,1346005 +1467,2024-01-06,Спорт,3,304652,913956 +1399,2024-02-20,Товары для дома,1,51892,51892 +1358,2024-03-05,Одежда,2,154273,308546 +1338,2024-01-28,Спорт,6,266519,1599114 +236,2024-03-17,Электроника,5,392670,1963350 +69,2024-02-21,Книги,3,473140,1419420 +690,2024-01-06,Товары для дома,3,294925,884775 +778,2024-02-28,Товары для дома,8,411184,3289472 +1122,2024-03-07,Одежда,7,105735,740145 +164,2024-02-20,Электроника,1,310323,310323 +168,2024-02-11,Спорт,5,176948,884740 +1186,2024-03-28,Товары для дома,3,181034,543102 +128,2024-02-21,Одежда,3,365539,1096617 +1113,2024-01-07,Книги,7,361628,2531396 +1204,2024-03-28,Товары для дома,3,39044,117132 +771,2024-02-25,Книги,2,55546,111092 +390,2024-01-18,Одежда,5,400641,2003205 +910,2024-01-26,Электроника,4,384022,1536088 +1055,2024-01-23,Спорт,6,456383,2738298 +1440,2024-02-18,Одежда,2,115654,231308 +246,2024-03-01,Спорт,6,182432,1094592 +503,2024-03-23,Одежда,7,192062,1344434 +1001,2024-01-07,Одежда,4,53089,212356 +490,2024-02-17,Электроника,5,484605,2423025 +674,2024-01-31,Товары для дома,5,445300,2226500 +114,2024-01-04,Товары для дома,7,346048,2422336 +1054,2024-01-31,Спорт,8,195280,1562240 +1254,2024-02-07,Книги,5,352157,1760785 +165,2024-01-11,Спорт,3,336986,1010958 +532,2024-01-11,Товары для дома,5,131390,656950 +911,2024-01-20,Спорт,1,3344,3344 +1238,2024-03-23,Электроника,2,377638,755276 +737,2024-02-16,Одежда,2,399165,798330 +678,2024-02-12,Книги,8,339061,2712488 +264,2024-02-19,Электроника,3,99935,299805 +912,2024-01-30,Одежда,1,283926,283926 +202,2024-03-11,Одежда,7,278356,1948492 +103,2024-02-16,Книги,6,471326,2827956 +252,2024-03-25,Электроника,8,455799,3646392 +36,2024-03-23,Книги,5,178350,891750 +730,2024-03-03,Одежда,7,119611,837277 +612,2024-02-08,Электроника,2,297776,595552 +1011,2024-01-12,Электроника,7,336523,2355661 +1087,2024-01-16,Книги,2,246697,493394 +1183,2024-01-18,Спорт,5,72447,362235 +171,2024-02-14,Книги,1,117557,117557 +839,2024-03-13,Спорт,6,446915,2681490 +1197,2024-03-23,Спорт,4,294268,1177072 +873,2024-02-16,Товары для дома,8,286449,2291592 +1008,2024-01-22,Одежда,2,334596,669192 +746,2024-02-04,Товары для дома,2,258539,517078 +83,2024-02-28,Книги,1,165768,165768 +449,2024-03-05,Спорт,3,276541,829623 +1130,2024-01-07,Товары для дома,1,52329,52329 +1425,2024-01-04,Одежда,6,18432,110592 +142,2024-02-01,Книги,2,77370,154740 +541,2024-03-02,Спорт,5,128387,641935 +1435,2024-03-29,Спорт,8,483440,3867520 +240,2024-02-25,Одежда,5,385108,1925540 +1012,2024-01-24,Спорт,6,194522,1167132 +1115,2024-03-01,Товары для дома,4,367982,1471928 +973,2024-01-08,Товары для дома,3,11489,34467 +1258,2024-01-25,Спорт,8,166612,1332896 +767,2024-03-10,Одежда,2,19276,38552 +536,2024-03-13,Книги,2,21598,43196 +1287,2024-03-15,Электроника,3,285397,856191 +1381,2024-03-10,Электроника,6,17073,102438 +62,2024-02-21,Одежда,2,381794,763588 +1013,2024-01-24,Книги,5,233715,1168575 +795,2024-03-16,Одежда,6,59891,359346 +683,2024-01-02,Товары для дома,2,111049,222098 +732,2024-01-11,Электроника,5,404839,2024195 +492,2024-02-25,Товары для дома,5,315860,1579300 +99,2024-03-12,Книги,2,5070,10140 +1260,2024-03-13,Одежда,6,297199,1783194 +146,2024-02-26,Электроника,7,321207,2248449 +551,2024-02-11,Электроника,6,489555,2937330 +1255,2024-01-13,Электроника,8,103504,828032 +584,2024-03-05,Электроника,8,406309,3250472 +1141,2024-03-13,Спорт,3,355674,1067022 +269,2024-02-14,Электроника,7,174295,1220065 +573,2024-03-16,Электроника,8,176357,1410856 +1311,2024-03-17,Книги,4,309643,1238572 +1445,2024-03-20,Одежда,8,237381,1899048 +35,2024-03-28,Электроника,5,463884,2319420 +740,2024-01-14,Книги,6,13769,82614 +560,2024-02-21,Книги,7,191857,1342999 +966,2024-03-31,Одежда,3,367296,1101888 +1375,2024-03-19,Электроника,1,3473,3473 +1225,2024-03-03,Одежда,4,22991,91964 +173,2024-01-03,Товары для дома,4,325759,1303036 +267,2024-02-08,Электроника,8,439079,3512632 +591,2024-03-31,Спорт,6,108674,652044 +1021,2024-03-01,Книги,7,156685,1096795 +1249,2024-01-27,Одежда,4,392323,1569292 +237,2024-02-26,Спорт,5,65198,325990 +888,2024-01-21,Одежда,5,260264,1301320 +939,2024-03-28,Книги,5,330458,1652290 +601,2024-03-22,Книги,2,122074,244148 +1334,2024-01-23,Электроника,8,194099,1552792 +1242,2024-02-18,Книги,8,207154,1657232 +1165,2024-03-25,Спорт,2,190471,380942 +172,2024-01-04,Товары для дома,4,497871,1991484 +522,2024-03-19,Книги,2,463600,927200 +468,2024-01-09,Спорт,1,58122,58122 +775,2024-02-14,Спорт,2,12878,25756 +1022,2024-01-05,Электроника,3,263246,789738 +552,2024-01-25,Товары для дома,8,400096,3200768 +352,2024-03-18,Книги,3,77770,233310 +1463,2024-02-16,Книги,4,465316,1861264 +22,2024-03-28,Книги,4,170018,680072 +345,2024-01-09,Спорт,6,249691,1498146 +710,2024-02-15,Спорт,2,140156,280312 +1466,2024-02-20,Товары для дома,1,413739,413739 +1160,2024-02-22,Электроника,1,18787,18787 +1395,2024-01-19,Товары для дома,8,419451,3355608 +850,2024-01-01,Спорт,2,111895,223790 +880,2024-02-05,Одежда,2,43829,87658 +272,2024-01-30,Спорт,1,448798,448798 +1133,2024-01-18,Товары для дома,6,347790,2086740 +660,2024-01-31,Книги,2,108047,216094 +423,2024-02-01,Спорт,8,370998,2967984 +200,2024-02-21,Товары для дома,5,362696,1813480 +760,2024-03-16,Товары для дома,1,286067,286067 +1482,2024-02-07,Одежда,6,429612,2577672 +273,2024-02-10,Спорт,7,390440,2733080 +1385,2024-03-27,Спорт,2,110495,220990 +155,2024-02-23,Товары для дома,7,32646,228522 +779,2024-02-14,Книги,8,249647,1997176 +205,2024-01-16,Товары для дома,6,378161,2268966 +652,2024-03-24,Одежда,2,451038,902076 +1039,2024-01-07,Спорт,5,390988,1954940 +1437,2024-03-17,Книги,6,121224,727344 +1066,2024-02-02,Спорт,5,114405,572025 +1301,2024-03-14,Товары для дома,3,310561,931683 +1449,2024-02-26,Книги,4,381214,1524856 +715,2024-01-08,Книги,3,333840,1001520 +177,2024-01-21,Книги,1,163074,163074 +791,2024-03-09,Одежда,6,98021,588126 +108,2024-01-04,Одежда,7,94037,658259 +514,2024-02-27,Спорт,2,90522,181044 +698,2024-01-24,Электроника,1,480720,480720 +226,2024-03-21,Одежда,2,110638,221276 +998,2024-02-13,Электроника,8,311444,2491552 +501,2024-01-19,Электроника,8,444948,3559584 +197,2024-03-12,Товары для дома,8,397497,3179976 +962,2024-03-09,Книги,4,427969,1711876 +1056,2024-02-14,Одежда,2,85729,171458 +1265,2024-02-29,Одежда,5,233496,1167480 +305,2024-03-27,Товары для дома,2,396141,792282 +75,2024-03-05,Электроника,3,482024,1446072 +44,2024-01-11,Спорт,2,383731,767462 +451,2024-02-02,Спорт,6,27358,164148 +526,2024-02-29,Электроника,6,356573,2139438 +1367,2024-02-06,Спорт,6,48764,292584 +580,2024-01-19,Товары для дома,1,430788,430788 +617,2024-01-24,Одежда,5,7385,36925 +1431,2024-01-12,Одежда,6,231663,1389978 +1195,2024-03-10,Одежда,8,16938,135504 +765,2024-02-18,Спорт,8,38780,310240 +1397,2024-01-18,Электроника,6,468331,2809986 +992,2024-02-18,Электроника,7,184147,1289029 +229,2024-03-29,Спорт,5,311329,1556645 +1423,2024-01-30,Одежда,8,129708,1037664 +1405,2024-03-14,Электроника,3,301935,905805 +555,2024-03-05,Товары для дома,4,239721,958884 +1276,2024-02-20,Электроника,1,190771,190771 +735,2024-02-19,Одежда,2,166031,332062 +661,2024-03-17,Спорт,1,17604,17604 +834,2024-03-15,Книги,8,1297,10376 +944,2024-02-20,Книги,7,260114,1820798 +1326,2024-03-14,Книги,1,273962,273962 +132,2024-02-06,Спорт,6,110197,661182 +520,2024-03-04,Одежда,6,13781,82686 +1457,2024-01-16,Товары для дома,7,402730,2819110 +1088,2024-03-01,Товары для дома,2,466316,932632 +608,2024-03-24,Товары для дома,1,301012,301012 +130,2024-03-19,Одежда,7,298376,2088632 +878,2024-02-24,Спорт,2,367951,735902 +897,2024-03-06,Книги,1,1347,1347 +460,2024-03-24,Товары для дома,3,175789,527367 +259,2024-03-11,Книги,4,213905,855620 +65,2024-02-29,Книги,8,130971,1047768 +43,2024-01-31,Товары для дома,2,30370,60740 +249,2024-03-25,Спорт,1,495554,495554 +753,2024-02-12,Одежда,7,230804,1615628 +1420,2024-01-04,Спорт,2,404192,808384 +667,2024-02-08,Товары для дома,4,459412,1837648 +949,2024-03-23,Спорт,7,154721,1083047 +1175,2024-02-27,Электроника,3,239803,719409 +150,2024-02-26,Одежда,4,40624,162496 +337,2024-03-16,Товары для дома,6,113221,679326 +27,2024-01-18,Электроника,5,129304,646520 +1091,2024-01-26,Спорт,8,179658,1437264 +1104,2024-01-22,Книги,5,34230,171150 +686,2024-02-06,Спорт,6,199577,1197462 +1162,2024-03-06,Товары для дома,8,294825,2358600 +705,2024-03-09,Спорт,1,289221,289221 +1452,2024-03-04,Спорт,1,194720,194720 +983,2024-03-19,Электроника,2,115813,231626 +825,2024-03-06,Книги,3,471941,1415823 +1448,2024-01-14,Одежда,3,147910,443730 +1230,2024-03-09,Спорт,2,434503,869006 +156,2024-02-19,Электроника,1,474396,474396 +789,2024-01-01,Товары для дома,4,369485,1477940 +979,2024-01-29,Электроника,3,348931,1046793 +356,2024-01-13,Книги,4,415811,1663244 +1108,2024-02-21,Товары для дома,4,10027,40108 +986,2024-03-22,Книги,6,464163,2784978 +1135,2024-01-12,Одежда,3,195362,586086 +469,2024-03-21,Электроника,4,270206,1080824 +629,2024-03-19,Товары для дома,3,115789,347367 +216,2024-01-24,Одежда,8,26937,215496 +1241,2024-03-18,Одежда,8,45354,362832 +376,2024-03-13,Спорт,2,344638,689276 +719,2024-02-04,Книги,5,24412,122060 +447,2024-01-25,Электроника,8,192855,1542840 +263,2024-02-01,Электроника,3,239488,718464 +233,2024-02-24,Электроника,4,60176,240704 +797,2024-03-19,Книги,3,309419,928257 +1019,2024-02-19,Электроника,7,429081,3003567 +758,2024-02-11,Одежда,7,197162,1380134 +274,2024-02-19,Товары для дома,8,347965,2783720 +1455,2024-03-10,Товары для дома,4,246493,985972 +28,2024-03-15,Электроника,7,224623,1572361 +1350,2024-01-12,Спорт,6,144671,868026 +892,2024-02-03,Электроника,2,373463,746926 +1040,2024-02-17,Одежда,5,10608,53040 +1284,2024-02-19,Спорт,1,246245,246245 +1317,2024-03-02,Товары для дома,1,345712,345712 +567,2024-01-26,Электроника,7,315865,2211055 +602,2024-02-22,Спорт,2,173169,346338 +1237,2024-03-27,Электроника,1,62027,62027 +343,2024-01-03,Одежда,1,91356,91356 +1069,2024-03-12,Электроника,5,339394,1696970 +380,2024-02-09,Одежда,2,378325,756650 +1471,2024-03-23,Электроника,2,80698,161396 +1236,2024-02-25,Книги,7,165887,1161209 +126,2024-03-20,Книги,5,164583,822915 +1239,2024-03-15,Книги,6,23864,143184 +1185,2024-01-26,Электроника,5,109950,549750 +1275,2024-01-18,Электроника,2,243638,487276 +1324,2024-03-17,Электроника,7,459679,3217753 +1081,2024-02-07,Спорт,3,51173,153519 +895,2024-02-17,Одежда,2,82476,164952 +889,2024-01-22,Товары для дома,5,194967,974835 +144,2024-01-07,Товары для дома,2,292242,584484 +1201,2024-01-26,Спорт,4,325354,1301416 +799,2024-01-15,Одежда,3,95969,287907 +1417,2024-01-31,Одежда,2,347091,694182 +1030,2024-03-30,Электроника,7,326662,2286634 +502,2024-01-05,Книги,4,66181,264724 +374,2024-01-24,Одежда,6,143273,859638 +1163,2024-02-13,Книги,4,190497,761988 +41,2024-03-17,Спорт,1,169952,169952 +354,2024-02-18,Электроника,5,313206,1566030 +1369,2024-02-10,Товары для дома,5,185356,926780 +887,2024-01-02,Товары для дома,1,371144,371144 +1322,2024-02-24,Одежда,8,70194,561552 +1393,2024-01-13,Одежда,4,377915,1511660 +361,2024-01-20,Спорт,2,360093,720186 +248,2024-02-12,Спорт,5,215821,1079105 +1429,2024-03-08,Электроника,5,335433,1677165 +858,2024-03-08,Книги,3,295327,885981 +1243,2024-01-21,Товары для дома,3,279691,839073 +671,2024-01-07,Спорт,6,180573,1083438 +893,2024-03-04,Электроника,6,238655,1431930 +935,2024-02-21,Спорт,4,448058,1792232 +1340,2024-02-19,Книги,2,333383,666766 +568,2024-03-05,Книги,1,21106,21106 +757,2024-02-07,Спорт,4,385286,1541144 +257,2024-01-04,Электроника,4,330314,1321256 +668,2024-02-22,Одежда,1,157550,157550 +884,2024-01-08,Книги,7,128178,897246 +375,2024-02-14,Товары для дома,3,3202,9606 +1495,2024-01-07,Товары для дома,2,192076,384152 +256,2024-02-06,Спорт,2,229700,459400 +531,2024-02-14,Электроника,5,496755,2483775 +1344,2024-02-19,Спорт,5,487947,2439735 +865,2024-03-11,Электроника,5,315097,1575485 +659,2024-03-25,Электроника,1,219803,219803 +637,2024-03-14,Товары для дома,3,281365,844095 +960,2024-03-15,Товары для дома,2,122035,244070 +896,2024-03-14,Книги,4,353434,1413736 +461,2024-01-05,Спорт,3,150408,451224 +435,2024-03-23,Спорт,6,351513,2109078 +1189,2024-03-27,Электроника,5,392099,1960495 +891,2024-02-24,Электроника,2,142597,285194 +436,2024-01-03,Одежда,3,190106,570318 +863,2024-02-24,Товары для дома,4,164891,659564 +426,2024-02-22,Одежда,1,406043,406043 +141,2024-03-30,Спорт,7,201316,1409212 +1097,2024-03-19,Спорт,7,227390,1591730 +1176,2024-03-04,Электроника,1,2275,2275 +448,2024-02-29,Одежда,7,403408,2823856 +596,2024-02-14,Спорт,5,484448,2422240 +650,2024-02-18,Спорт,7,235163,1646141 +74,2024-02-10,Книги,8,29972,239776 +942,2024-02-12,Книги,8,64240,513920 +937,2024-01-16,Книги,4,6269,25076 +129,2024-01-25,Спорт,3,220435,661305 +296,2024-02-26,Одежда,5,495576,2477880 +820,2024-03-31,Спорт,3,319953,959859 +428,2024-02-12,Электроника,7,49549,346843 +956,2024-03-13,Одежда,7,263399,1843793 +1410,2024-03-21,Электроника,7,321027,2247189 +193,2024-01-24,Товары для дома,6,255617,1533702 +578,2024-01-07,Спорт,3,305935,917805 +915,2024-02-23,Книги,3,257965,773895 +599,2024-01-14,Электроника,4,322793,1291172 +1470,2024-03-21,Книги,6,31485,188910 +853,2024-02-24,Товары для дома,8,363873,2910984 +1364,2024-02-18,Товары для дома,4,332222,1328888 +963,2024-03-14,Спорт,6,443813,2662878 +392,2024-02-25,Товары для дома,7,92115,644805 +326,2024-03-16,Товары для дома,7,389163,2724141 +404,2024-01-29,Товары для дома,2,174624,349248 +1488,2024-03-19,Одежда,7,148442,1039094 +1031,2024-01-15,Товары для дома,3,217288,651864 +801,2024-03-14,Спорт,3,201175,603525 +1037,2024-01-19,Электроника,7,324139,2268973 +113,2024-02-09,Товары для дома,4,430198,1720792 +368,2024-01-14,Электроника,4,302996,1211984 +899,2024-02-19,Товары для дома,3,482464,1447392 +55,2024-01-10,Товары для дома,5,269566,1347830 +1147,2024-03-26,Одежда,2,457779,915558 +64,2024-01-18,Товары для дома,5,221188,1105940 +302,2024-03-13,Книги,8,453545,3628360 +836,2024-03-09,Товары для дома,7,208518,1459626 +1062,2024-03-23,Электроника,1,90808,90808 +523,2024-02-09,Спорт,7,208751,1461257 +1286,2024-03-31,Одежда,5,273350,1366750 +353,2024-02-05,Электроника,6,327323,1963938 +604,2024-03-11,Товары для дома,7,487116,3409812 +1151,2024-01-02,Товары для дома,8,337327,2698616 +833,2024-02-28,Спорт,6,498207,2989242 +907,2024-01-02,Товары для дома,5,193420,967100 +1053,2024-03-22,Книги,1,483957,483957 +201,2024-03-25,Одежда,8,304903,2439224 +458,2024-01-31,Книги,6,202463,1214778 +400,2024-03-29,Одежда,2,482225,964450 +1159,2024-03-24,Книги,7,9317,65219 +1494,2024-03-08,Электроника,5,327141,1635705 +1126,2024-01-15,Электроника,8,437903,3503224 +1210,2024-03-21,Одежда,8,322757,2582056 +151,2024-02-04,Одежда,2,176081,352162 +1428,2024-03-16,Спорт,7,313307,2193149 +143,2024-02-24,Товары для дома,8,114736,917888 +1014,2024-02-26,Одежда,4,243825,975300 +93,2024-02-04,Электроника,4,147722,590888 +63,2024-02-01,Товары для дома,8,100449,803592 +1218,2024-03-12,Книги,2,431850,863700 +754,2024-03-24,Товары для дома,5,311634,1558170 +947,2024-02-05,Товары для дома,1,233839,233839 +923,2024-03-30,Одежда,6,436156,2616936 +72,2024-01-20,Одежда,4,99562,398248 +1325,2024-02-02,Книги,1,99102,99102 +788,2024-02-27,Спорт,7,310486,2173402 +1226,2024-02-11,Книги,2,269429,538858 +1314,2024-01-20,Книги,3,317463,952389 +1298,2024-03-02,Спорт,8,354015,2832120 +812,2024-02-28,Спорт,2,296564,593128 +1018,2024-03-16,Электроника,1,119283,119283 +475,2024-03-22,Одежда,5,202838,1014190 +708,2024-01-14,Книги,3,481322,1443966 +499,2024-03-26,Спорт,6,334241,2005446 +694,2024-03-04,Одежда,5,288696,1443480 +80,2024-02-23,Электроника,6,344653,2067918 +178,2024-02-09,Спорт,7,301884,2113188 +242,2024-03-27,Одежда,1,430662,430662 +558,2024-02-06,Книги,2,281381,562762 +351,2024-02-26,Книги,6,38531,231186 +581,2024-03-14,Книги,4,497133,1988532 +1389,2024-02-16,Спорт,7,96424,674968 +442,2024-01-24,Электроника,3,435865,1307595 +809,2024-03-03,Книги,1,87689,87689 +759,2024-02-16,Электроника,4,59711,238844 +804,2024-01-18,Одежда,8,98094,784752 +394,2024-01-10,Книги,7,208180,1457260 +829,2024-03-27,Спорт,3,205889,617667 +1139,2024-01-17,Книги,3,364994,1094982 +562,2024-02-16,Одежда,2,290049,580098 +250,2024-02-28,Одежда,5,46169,230845 +245,2024-03-22,Спорт,2,426899,853798 +1376,2024-03-02,Электроника,6,194614,1167684 +605,2024-03-24,Спорт,8,490227,3921816 +411,2024-03-28,Электроника,6,484523,2907138 +1035,2024-02-03,Спорт,8,200826,1606608 +1269,2024-02-03,Книги,2,384589,769178 +773,2024-02-27,Спорт,8,196147,1569176 +691,2024-01-03,Электроника,7,136721,957047 +570,2024-03-07,Товары для дома,3,239594,718782 +334,2024-01-07,Одежда,4,412507,1650028 +110,2024-01-21,Книги,7,412812,2889684 +1136,2024-01-15,Спорт,8,210123,1680984 +815,2024-03-10,Спорт,2,114579,229158 +1433,2024-01-02,Электроника,3,49,147 +131,2024-03-11,Книги,5,437113,2185565 +1002,2024-01-25,Электроника,5,214581,1072905 +1421,2024-01-14,Электроника,3,137601,412803 +357,2024-02-25,Товары для дома,7,236745,1657215 +1257,2024-01-13,Электроника,2,149494,298988 +1051,2024-02-16,Товары для дома,5,369432,1847160 +1164,2024-02-28,Электроника,8,174050,1392400 +835,2024-03-22,Одежда,2,348203,696406 +360,2024-02-24,Одежда,6,163853,983118 +116,2024-02-14,Электроника,7,336322,2354254 +487,2024-01-16,Одежда,7,419086,2933602 +1025,2024-01-06,Книги,7,221971,1553797 +1331,2024-03-13,Электроника,5,191703,958515 +500,2024-03-06,Товары для дома,1,420006,420006 +1010,2024-02-20,Спорт,5,246911,1234555 +1041,2024-02-09,Спорт,2,146983,293966 +838,2024-02-06,Электроника,3,177081,531243 +188,2024-02-29,Электроника,5,228367,1141835 +1403,2024-02-14,Спорт,2,10400,20800 +373,2024-03-18,Одежда,1,487108,487108 +265,2024-01-09,Спорт,6,144834,869004 +1386,2024-02-11,Электроника,5,189584,947920 +148,2024-02-27,Товары для дома,5,135892,679460 +230,2024-01-05,Одежда,5,121361,606805 +238,2024-03-30,Одежда,8,211031,1688248 +482,2024-01-06,Товары для дома,1,414770,414770 +831,2024-02-18,Книги,2,236974,473948 +755,2024-02-11,Товары для дома,8,316257,2530056 +959,2024-01-08,Спорт,6,423968,2543808 +100,2024-03-29,Товары для дома,1,473919,473919 +480,2024-03-21,Товары для дома,2,95567,191134 +1244,2024-02-20,Электроника,5,417738,2088690 +135,2024-02-06,Электроника,6,270246,1621476 +1248,2024-03-09,Книги,5,287062,1435310 +1442,2024-02-06,Электроника,5,339979,1699895 +1093,2024-03-03,Товары для дома,6,174394,1046364 +1145,2024-01-06,Одежда,6,33207,199242 +203,2024-03-11,Одежда,8,173430,1387440 +1082,2024-02-03,Электроника,3,380207,1140621 +725,2024-02-19,Товары для дома,2,396157,792314 +365,2024-03-26,Спорт,6,64085,384510 +632,2024-03-09,Товары для дома,4,420477,1681908 +457,2024-01-07,Электроника,6,207857,1247142 +948,2024-03-19,Электроника,4,324627,1298508 +607,2024-02-06,Книги,2,338637,677274 +611,2024-02-07,Книги,1,459666,459666 +1305,2024-03-25,Одежда,2,430600,861200 +1380,2024-01-07,Спорт,8,275637,2205096 +437,2024-01-28,Спорт,4,179167,716668 +781,2024-02-08,Книги,1,23427,23427 +56,2024-03-26,Товары для дома,3,254497,763491 +393,2024-03-09,Товары для дома,6,368927,2213562 +1245,2024-03-22,Одежда,6,75538,453228 +1373,2024-03-20,Товары для дома,2,186661,373322 +1112,2024-03-17,Книги,1,25146,25146 +841,2024-01-13,Спорт,1,328299,328299 +134,2024-03-06,Товары для дома,2,248086,496172 +1065,2024-02-18,Одежда,8,446477,3571816 +1412,2024-01-30,Одежда,5,164355,821775 +554,2024-03-04,Книги,7,12152,85064 +1259,2024-02-12,Одежда,3,323141,969423 +628,2024-03-29,Одежда,6,61560,369360 +739,2024-02-27,Электроника,7,292021,2044147 +73,2024-01-08,Электроника,1,303658,303658 +1475,2024-01-18,Книги,8,131438,1051504 +1003,2024-03-25,Одежда,4,147600,590400 +588,2024-03-10,Одежда,8,185749,1485992 +291,2024-03-20,Товары для дома,8,358160,2865280 +1491,2024-01-17,Книги,4,93659,374636 +1070,2024-02-08,Книги,8,358830,2870640 +716,2024-01-11,Спорт,6,262070,1572420 +563,2024-02-19,Спорт,5,264376,1321880 +877,2024-03-21,Электроника,7,373623,2615361 +1240,2024-03-05,Одежда,5,55646,278230 +212,2024-02-05,Книги,5,23864,119320 +105,2024-02-15,Электроника,7,409006,2863042 +527,2024-01-17,Электроника,3,460304,1380912 +1302,2024-03-21,Книги,3,268773,806319 +638,2024-02-11,Электроника,8,447997,3583976 +118,2024-01-04,Одежда,3,60473,181419 +281,2024-02-12,Электроника,7,446873,3128111 +162,2024-03-26,Спорт,3,356066,1068198 +822,2024-01-08,Одежда,5,298884,1494420 +280,2024-03-20,Спорт,2,363177,726354 +879,2024-03-22,Электроника,3,281315,843945 +688,2024-02-29,Спорт,6,51700,310200 +452,2024-03-11,Книги,2,489839,979678 +327,2024-03-24,Спорт,7,51916,363412 +1309,2024-03-20,Электроника,5,345846,1729230 +1177,2024-03-11,Спорт,8,490371,3922968 +294,2024-03-26,Спорт,5,4927,24635 +198,2024-03-23,Спорт,8,373211,2985688 +206,2024-01-16,Электроника,3,389484,1168452 +329,2024-02-26,Товары для дома,6,233149,1398894 +1075,2024-01-04,Спорт,5,343619,1718095 +655,2024-02-08,Электроника,7,242748,1699236 +1208,2024-01-01,Спорт,3,173311,519933 +1454,2024-02-04,Спорт,2,406666,813332 +1365,2024-02-10,Одежда,1,216230,216230 +1282,2024-01-09,Одежда,4,138600,554400 +1182,2024-02-20,Одежда,8,179757,1438056 +1330,2024-02-03,Электроника,7,448255,3137785 +1038,2024-01-05,Одежда,4,207510,830040 +48,2024-01-28,Электроника,4,487019,1948076 +1285,2024-01-06,Одежда,2,340014,680028 +1068,2024-03-15,Книги,6,53642,321852 +918,2024-01-11,Книги,3,304492,913476 +609,2024-01-23,Товары для дома,1,219093,219093 +1273,2024-03-24,Товары для дома,6,406427,2438562 +46,2024-03-25,Электроника,3,249185,747555 +319,2024-03-20,Электроника,6,463594,2781564 +119,2024-03-15,Книги,2,139181,278362 +535,2024-01-22,Электроника,6,345366,2072196 +731,2024-02-25,Электроника,7,97381,681667 +397,2024-03-31,Спорт,5,335619,1678095 +471,2024-03-19,Товары для дома,7,184978,1294846 +987,2024-02-27,Одежда,4,5975,23900 +844,2024-03-29,Товары для дома,5,476792,2383960 +211,2024-01-02,Электроника,3,371206,1113618 +1117,2024-02-23,Книги,5,346903,1734515 +693,2024-01-30,Электроника,4,199146,796584 +529,2024-01-16,Товары для дома,5,271635,1358175 +1090,2024-02-22,Товары для дома,3,28345,85035 +1310,2024-01-22,Одежда,8,379683,3037464 +1057,2024-02-06,Спорт,1,14392,14392 +318,2024-03-27,Спорт,1,122591,122591 +537,2024-01-06,Электроника,5,497312,2486560 +751,2024-01-14,Одежда,1,71036,71036 +1430,2024-02-14,Электроника,4,252525,1010100 +1250,2024-02-22,Электроника,3,474810,1424430 +195,2024-03-12,Электроника,4,5323,21292 +158,2024-02-15,Спорт,7,156560,1095920 +1479,2024-02-11,Спорт,5,383990,1919950 +495,2024-03-18,Спорт,3,376263,1128789 +1172,2024-02-28,Товары для дома,6,432304,2593824 +1370,2024-01-24,Товары для дома,8,496563,3972504 +1342,2024-01-12,Одежда,4,33597,134388 +95,2024-02-02,Книги,2,474658,949316 +862,2024-01-16,Спорт,6,309107,1854642 +39,2024-03-21,Электроника,4,156472,625888 +384,2024-02-23,Товары для дома,2,143219,286438 +1374,2024-01-16,Книги,8,482444,3859552 +946,2024-01-28,Товары для дома,5,476214,2381070 +1047,2024-02-09,Электроника,7,372019,2604133 +929,2024-02-09,Одежда,2,242928,485856 +222,2024-03-07,Спорт,8,199428,1595424 +310,2024-03-10,Одежда,5,459518,2297590 +463,2024-01-11,Одежда,4,9964,39856 +381,2024-01-07,Товары для дома,1,81569,81569 +1015,2024-02-04,Книги,3,295828,887484 +898,2024-02-01,Спорт,6,24108,144648 +89,2024-03-19,Электроника,1,423153,423153 +821,2024-03-19,Товары для дома,4,73000,292000 +279,2024-03-01,Одежда,6,409745,2458470 +33,2024-03-17,Электроника,5,245393,1226965 +727,2024-01-13,Товары для дома,2,229161,458322 +323,2024-03-04,Книги,4,60881,243524 +723,2024-01-21,Товары для дома,7,295677,2069739 +856,2024-02-08,Спорт,3,71896,215688 +770,2024-03-13,Спорт,6,338183,2029098 +1496,2024-01-02,Товары для дома,8,487699,3901592 +964,2024-01-23,Товары для дома,6,92328,553968 +192,2024-02-13,Спорт,6,15048,90288 +399,2024-01-22,Электроника,8,420124,3360992 +621,2024-03-26,Товары для дома,3,50010,150030 +585,2024-01-08,Товары для дома,4,370030,1480120 +1335,2024-02-02,Электроника,6,160775,964650 +548,2024-02-04,Товары для дома,3,235718,707154 +642,2024-02-28,Книги,8,295652,2365216 +1315,2024-03-01,Электроника,1,472703,472703 +348,2024-03-25,Одежда,8,273391,2187128 +32,2024-03-17,Спорт,7,33307,233149 +288,2024-02-15,Спорт,3,196525,589575 +153,2024-03-29,Товары для дома,2,80114,160228 +68,2024-02-22,Спорт,4,254616,1018464 +902,2024-02-04,Книги,6,433061,2598366 +978,2024-03-24,Товары для дома,6,166348,998088 +702,2024-01-28,Спорт,6,265150,1590900 +982,2024-03-13,Товары для дома,6,16978,101868 +1461,2024-01-21,Книги,2,329864,659728 +20,2024-03-09,Товары для дома,3,1250,3750 +549,2024-01-13,Одежда,7,26532,185724 +569,2024-01-18,Одежда,8,374128,2993024 +1167,2024-02-13,Одежда,6,186196,1117176 +695,2024-03-03,Спорт,8,379353,3034824 +743,2024-02-19,Книги,4,408510,1634040 +579,2024-03-08,Электроника,7,329791,2308537 +951,2024-02-05,Товары для дома,7,200811,1405677 +534,2024-03-05,Товары для дома,3,336063,1008189 +58,2024-03-01,Спорт,4,423361,1693444 +761,2024-02-29,Товары для дома,8,494391,3955128 +872,2024-02-10,Спорт,7,69198,484386 +803,2024-03-12,Спорт,5,87486,437430 +1366,2024-03-30,Одежда,4,436301,1745204 +344,2024-01-17,Спорт,2,388874,777748 +550,2024-03-19,Товары для дома,3,219224,657672 +472,2024-01-24,Книги,6,348322,2089932 +643,2024-03-27,Одежда,1,423057,423057 +1489,2024-03-23,Книги,2,168834,337668 +494,2024-03-25,Одежда,8,155001,1240008 +140,2024-02-23,Электроника,4,464591,1858364 +662,2024-02-01,Книги,7,388257,2717799 +955,2024-03-10,Спорт,6,409698,2458188 +1327,2024-02-18,Товары для дома,6,343171,2059026 +486,2024-01-07,Одежда,5,453928,2269640 +491,2024-01-11,Спорт,2,381201,762402 +970,2024-03-18,Книги,8,114719,917752 +1293,2024-03-05,Товары для дома,8,462440,3699520 +339,2024-02-05,Товары для дома,3,450053,1350159 +886,2024-02-09,Товары для дома,2,349218,698436 +1192,2024-03-26,Товары для дома,5,29678,148390 +30,2024-01-12,Книги,2,396248,792496 +1184,2024-03-30,Одежда,4,287209,1148836 +1426,2024-03-01,Электроника,5,244944,1224720 +916,2024-02-05,Книги,4,48773,195092 +1320,2024-01-30,Спорт,7,492004,3444028 +1044,2024-01-25,Товары для дома,7,231587,1621109 +870,2024-03-04,Электроника,2,334539,669078 +703,2024-01-08,Электроника,8,323924,2591392 +117,2024-03-27,Электроника,6,442322,2653932 +1114,2024-02-26,Книги,5,199363,996815 +786,2024-01-24,Спорт,7,335796,2350572 +332,2024-01-16,Спорт,2,497555,995110 +941,2024-03-23,Товары для дома,2,232486,464972 +1205,2024-03-06,Спорт,1,62576,62576 +1232,2024-02-12,Книги,2,19864,39728 +316,2024-02-28,Одежда,7,193246,1352722 +1083,2024-03-28,Одежда,2,471645,943290 +1318,2024-03-27,Спорт,7,340385,2382695 +261,2024-03-04,Одежда,5,488979,2444895 +289,2024-02-01,Спорт,3,278485,835455 +707,2024-01-03,Спорт,3,263306,789918 +207,2024-01-25,Спорт,5,113448,567240 +656,2024-03-09,Товары для дома,4,198851,795404 +218,2024-03-03,Электроника,1,38841,38841 +1476,2024-03-31,Электроника,5,229377,1146885 +826,2024-02-22,Книги,5,481700,2408500 +1198,2024-03-06,Одежда,1,411203,411203 +359,2024-02-23,Книги,6,382528,2295168 +1460,2024-03-01,Одежда,6,204013,1224078 +1268,2024-01-18,Электроника,4,467297,1869188 +1095,2024-02-05,Товары для дома,3,109777,329331 +425,2024-02-16,Одежда,7,195482,1368374 +1036,2024-01-05,Одежда,7,90283,631981 +1391,2024-02-21,Спорт,3,146607,439821 +994,2024-01-21,Книги,1,236605,236605 +1153,2024-03-03,Товары для дома,6,168105,1008630 +1,2024-03-22,Книги,5,58370,291850 +121,2024-02-25,Электроника,2,317829,635658 +1086,2024-02-03,Одежда,8,307008,2456064 +1356,2024-03-14,Одежда,3,2439,7317 +477,2024-01-31,Книги,6,384273,2305638 +25,2024-01-28,Спорт,7,343639,2405473 +122,2024-02-19,Электроника,4,471600,1886400 +1486,2024-03-25,Спорт,4,282569,1130276 +1392,2024-03-14,Электроника,4,68755,275020 +726,2024-03-05,Одежда,1,390834,390834 +239,2024-02-26,Электроника,1,42175,42175 +1216,2024-03-25,Одежда,6,174003,1044018 +1060,2024-02-04,Спорт,1,341620,341620 +828,2024-01-19,Одежда,4,372976,1491904 +1312,2024-02-18,Товары для дома,2,202094,404188 +1477,2024-03-10,Спорт,4,365449,1461796 +648,2024-02-06,Товары для дома,3,214365,643095 +747,2024-01-22,Одежда,7,227896,1595272 +533,2024-01-17,Одежда,2,327692,655384 +509,2024-01-04,Товары для дома,8,385706,3085648 +577,2024-03-17,Одежда,4,248822,995288 +630,2024-03-02,Спорт,6,80314,481884 +133,2024-02-29,Спорт,4,231624,926496 +1116,2024-03-29,Книги,5,359526,1797630 +639,2024-01-15,Товары для дома,8,356671,2853368 +589,2024-01-25,Одежда,5,129248,646240 +539,2024-03-20,Книги,8,335016,2680128 +266,2024-03-05,Книги,5,140076,700380 +325,2024-02-17,Электроника,7,351528,2460696 +869,2024-03-04,Книги,4,202316,809264 +1296,2024-02-16,Книги,4,315633,1262532 +1138,2024-02-23,Товары для дома,2,340183,680366 +295,2024-03-27,Товары для дома,2,286575,573150 +724,2024-03-27,Электроника,6,470038,2820228 +1105,2024-02-07,Электроника,6,239037,1434222 +1207,2024-01-17,Электроника,5,84374,421870 +1443,2024-02-22,Книги,3,98567,295701 +742,2024-02-19,Одежда,7,6471,45297 +496,2024-03-29,Одежда,8,232736,1861888 +976,2024-02-13,Одежда,3,158212,474636 +542,2024-02-28,Книги,3,38259,114777 +1416,2024-01-22,Книги,3,96410,289230 +748,2024-02-08,Книги,6,253877,1523262 +1493,2024-01-05,Спорт,8,299375,2395000 +974,2024-01-15,Электроника,6,443800,2662800 +60,2024-02-24,Спорт,1,215536,215536 +627,2024-02-09,Спорт,5,83738,418690 +928,2024-03-09,Товары для дома,8,187846,1502768 +1372,2024-01-27,Товары для дома,4,120171,480684 +215,2024-03-01,Спорт,6,250985,1505910 +1329,2024-02-24,Электроника,5,341614,1708070 +1178,2024-03-06,Товары для дома,3,409512,1228536 +540,2024-03-21,Одежда,5,286040,1430200 +338,2024-01-19,Электроника,1,413477,413477 +1129,2024-02-28,Одежда,8,155201,1241608 +1170,2024-02-02,Товары для дома,4,320263,1281052 +712,2024-03-30,Одежда,2,118415,236830 +125,2024-02-16,Книги,6,226125,1356750 +138,2024-01-04,Товары для дома,8,24230,193840 +483,2024-02-10,Одежда,7,489356,3425492 +300,2024-03-14,Одежда,1,155123,155123 +1125,2024-01-31,Книги,2,1436,2872 +564,2024-03-20,Электроника,2,356725,713450 +864,2024-02-05,Книги,4,337967,1351868 +438,2024-01-29,Товары для дома,2,72124,144248 +777,2024-01-19,Одежда,6,182625,1095750 +70,2024-02-18,Спорт,5,1131,5655 +996,2024-01-14,Одежда,3,38903,116709 +1227,2024-01-22,Электроника,1,405442,405442 +1377,2024-03-04,Электроника,5,470875,2354375 +1161,2024-01-12,Электроника,5,415123,2075615 +331,2024-01-08,Одежда,4,208740,834960 +1354,2024-02-14,Одежда,4,427565,1710260 +1050,2024-02-01,Спорт,1,17339,17339 +96,2024-03-22,Одежда,1,222076,222076 +37,2024-02-25,Спорт,1,82921,82921 +954,2024-02-18,Одежда,8,409950,3279600 +1071,2024-01-09,Одежда,6,176310,1057860 +593,2024-02-06,Электроника,7,63898,447286 +768,2024-01-14,Товары для дома,6,403154,2418924 +467,2024-02-23,Электроника,8,334995,2679960 +182,2024-03-09,Одежда,2,224594,449188 +576,2024-02-23,Одежда,1,306029,306029 +807,2024-03-12,Спорт,7,264996,1854972 +587,2024-02-10,Спорт,6,90798,544788 +610,2024-02-20,Спорт,3,413119,1239357 +1292,2024-03-02,Электроника,1,465134,465134 +709,2024-01-31,Электроника,5,100628,503140 +677,2024-02-19,Одежда,4,127328,509312 +626,2024-01-08,Книги,8,350113,2800904 +1077,2024-02-19,Книги,4,386260,1545040 +1336,2024-03-31,Товары для дома,2,208735,417470 +166,2024-02-29,Книги,5,95279,476395 +183,2024-03-05,Одежда,1,339500,339500 +427,2024-03-21,Одежда,2,339375,678750 +1253,2024-03-11,Электроника,2,241836,483672 +1497,2024-01-11,Книги,6,245398,1472388 +1045,2024-03-03,Электроника,6,398194,2389164 +1404,2024-02-14,Электроника,4,454751,1819004 +340,2024-03-10,Товары для дома,2,131415,262830 +306,2024-03-21,Книги,5,338869,1694345 +618,2024-03-13,Товары для дома,3,353581,1060743 +859,2024-02-26,Товары для дома,3,184124,552372 +1033,2024-01-14,Книги,5,295009,1475045 +1215,2024-01-12,Товары для дома,4,183188,732752 +1424,2024-03-21,Товары для дома,3,66277,198831 +1462,2024-02-02,Одежда,4,252303,1009212 +149,2024-03-07,Товары для дома,5,254069,1270345 +1211,2024-03-14,Одежда,2,288443,576886 +358,2024-02-13,Спорт,7,433806,3036642 +669,2024-03-12,Электроника,3,497298,1491894 +57,2024-03-14,Спорт,4,302101,1208404 +152,2024-01-18,Товары для дома,7,79079,553553 +190,2024-02-05,Спорт,4,462229,1848916 +51,2024-01-29,Одежда,1,33569,33569 +213,2024-03-30,Товары для дома,8,494975,3959800 +1121,2024-01-26,Товары для дома,5,319293,1596465 +840,2024-03-28,Книги,1,399641,399641 +571,2024-02-11,Электроника,6,488306,2929836 +644,2024-02-20,Книги,4,133409,533636 +635,2024-01-10,Электроника,2,480901,961802 +285,2024-01-13,Книги,8,398653,3189224 +1152,2024-03-04,Товары для дома,2,455825,911650 +1017,2024-03-26,Электроника,7,180246,1261722 +251,2024-02-11,Спорт,1,60777,60777 +615,2024-02-04,Книги,6,101089,606534 +1379,2024-02-20,Электроника,3,116441,349323 +1478,2024-03-13,Электроника,6,97847,587082 +1351,2024-03-26,Спорт,4,207169,828676 +420,2024-02-11,Спорт,3,317198,951594 +1368,2024-01-10,Товары для дома,8,290745,2325960 +488,2024-02-21,Спорт,7,389708,2727956 +676,2024-03-12,Спорт,3,216362,649086 +1080,2024-01-22,Электроника,3,440737,1322211 +223,2024-02-08,Электроника,7,450976,3156832 +244,2024-02-05,Электроника,7,95153,666071 +1306,2024-01-28,Электроника,8,235512,1884096 +904,2024-01-29,Электроника,1,421705,421705 +1490,2024-03-07,Книги,1,345449,345449 +6,2024-03-12,Не указана,7,104249,729743 +827,2024-03-24,Товары для дома,4,66526,266104 +557,2024-02-06,Электроника,8,259468,2075744 +511,2024-02-03,Одежда,8,406305,3250440 +1110,2024-01-16,Книги,7,192200,1345400 +1020,2024-03-09,Спорт,4,360222,1440888 +1465,2024-01-02,Одежда,2,87746,175492 +26,2024-03-23,Товары для дома,5,240571,1202855 +519,2024-01-26,Товары для дома,4,415271,1661084 +1119,2024-01-14,Электроника,2,268218,536436 +1148,2024-02-25,Товары для дома,8,346929,2775432 +241,2024-01-04,Товары для дома,1,47882,47882 +371,2024-01-15,Одежда,4,399825,1599300 +592,2024-03-02,Электроника,5,182874,914370 +914,2024-01-14,Электроника,4,107581,430324 +634,2024-03-08,Электроника,6,234225,1405350 +631,2024-02-23,Электроника,8,368020,2944160 +860,2024-02-22,Спорт,4,323002,1292008 +106,2024-03-20,Товары для дома,4,392943,1571772 +1487,2024-03-08,Спорт,3,358207,1074621 +297,2024-03-22,Одежда,8,222461,1779688 +333,2024-03-25,Электроника,1,111205,111205 +308,2024-01-17,Одежда,6,47256,283536 +687,2024-02-09,Одежда,8,137134,1097072 +350,2024-02-21,Книги,8,223491,1787928 +1252,2024-01-25,Товары для дома,1,60096,60096 +1107,2024-03-03,Товары для дома,3,188351,565053 +776,2024-02-07,Книги,2,218091,436182 +328,2024-02-05,Одежда,4,17153,68612 +1411,2024-01-10,Товары для дома,6,41478,248868 +787,2024-01-04,Электроника,4,386604,1546416 +1328,2024-02-22,Книги,3,189934,569802 +744,2024-03-14,Товары для дома,7,273209,1912463 +921,2024-03-25,Товары для дома,5,68529,342645 +234,2024-03-23,Одежда,3,78114,234342 +187,2024-03-19,Электроника,8,423730,3389840 +254,2024-03-20,Спорт,8,396595,3172760 +1128,2024-01-13,Одежда,4,474365,1897460 +664,2024-01-08,Электроника,5,73472,367360 +513,2024-01-26,Товары для дома,2,64298,128596 +1343,2024-02-17,Электроника,1,41964,41964 +932,2024-01-12,Товары для дома,6,372852,2237112 +414,2024-02-05,Книги,6,310075,1860450 +930,2024-01-12,Одежда,1,82636,82636 +1474,2024-01-25,Спорт,6,11196,67176 +52,2024-03-16,Товары для дома,4,290415,1161660 +924,2024-02-27,Товары для дома,2,142584,285168 +1307,2024-03-02,Товары для дома,7,89427,625989 +847,2024-02-17,Товары для дома,1,348394,348394 +1213,2024-01-24,Книги,3,272948,818844 +278,2024-01-19,Товары для дома,2,214947,429894 +369,2024-01-20,Спорт,4,344319,1377276 +232,2024-03-28,Одежда,4,122382,489528 +1228,2024-03-21,Товары для дома,4,34327,137308 +186,2024-02-25,Электроника,5,92347,461735 +926,2024-01-20,Товары для дома,8,55396,443168 +950,2024-03-11,Книги,2,251151,502302 +292,2024-03-15,Товары для дома,8,75035,600280 +1059,2024-01-29,Товары для дома,4,339414,1357656 +1279,2024-01-23,Электроника,3,296935,890805 +603,2024-03-28,Товары для дома,1,404104,404104 +866,2024-03-29,Одежда,4,14064,56256 +341,2024-03-25,Книги,3,454269,1362807 +945,2024-03-28,Товары для дома,6,223695,1342170 +586,2024-03-12,Спорт,7,170420,1192940 +624,2024-02-04,Одежда,1,172819,172819 +816,2024-03-24,Товары для дома,5,393922,1969610 +901,2024-02-11,Спорт,6,130162,780972 +597,2024-03-02,Товары для дома,5,112191,560955 +1481,2024-01-09,Товары для дома,8,278469,2227752 +1332,2024-03-28,Товары для дома,7,208381,1458667 +1058,2024-01-21,Электроника,4,447649,1790596 +1132,2024-01-15,Книги,1,49807,49807 +81,2024-02-03,Одежда,4,107091,428364 +811,2024-01-29,Одежда,3,281862,845586 +1063,2024-01-29,Электроника,5,132326,661630 +504,2024-03-13,Электроника,3,16980,50940 +87,2024-02-01,Одежда,3,193739,581217 +936,2024-01-13,Книги,3,242244,726732 +925,2024-01-26,Электроника,2,71362,142724 +224,2024-02-09,Электроника,1,298126,298126 +1190,2024-02-24,Книги,2,423785,847570 +79,2024-03-15,Книги,2,311700,623400 +1076,2024-02-03,Спорт,7,475483,3328381 +1099,2024-01-05,Товары для дома,6,279856,1679136 +1339,2024-03-11,Книги,3,321927,965781 +641,2024-01-08,Товары для дома,7,237730,1664110 +1233,2024-01-07,Одежда,2,93320,186640 +86,2024-01-17,Одежда,2,489297,978594 +830,2024-03-14,Одежда,7,331561,2320927 +876,2024-01-08,Спорт,5,497382,2486910 +506,2024-02-26,Книги,3,400077,1200231 +1222,2024-01-15,Одежда,5,202311,1011555 +666,2024-03-14,Одежда,4,313482,1253928 +1214,2024-02-23,Электроника,7,284731,1993117 +900,2024-01-05,Спорт,4,289861,1159444 +363,2024-02-25,Одежда,3,50628,151884 +136,2024-01-12,Товары для дома,5,429090,2145450 +419,2024-02-27,Электроника,4,476604,1906416 +416,2024-02-27,Книги,6,19718,118308 +456,2024-02-14,Книги,7,487836,3414852 +846,2024-03-24,Одежда,2,188972,377944 +553,2024-03-06,Спорт,5,244746,1223730 +31,2024-01-20,Товары для дома,7,328963,2302741 +837,2024-01-28,Одежда,6,259374,1556244 +67,2024-01-12,Товары для дома,3,485684,1457052 +464,2024-01-20,Электроника,7,287732,2014124 +1480,2024-03-17,Электроника,3,479448,1438344 +336,2024-01-09,Электроника,4,435064,1740256 +1398,2024-03-03,Одежда,1,157305,157305 +971,2024-01-01,Электроника,4,173925,695700 +1007,2024-01-26,Книги,4,50850,203400 +794,2024-03-17,Электроника,7,203759,1426313 +377,2024-01-19,Книги,2,388482,776964 +1283,2024-01-06,Товары для дома,6,350532,2103192 +961,2024-02-01,Товары для дома,5,344387,1721935 +1352,2024-03-07,Книги,2,8057,16114 +275,2024-01-05,Электроника,6,66190,397140 +977,2024-01-21,Спорт,8,383964,3071712 +163,2024-02-29,Товары для дома,1,482105,482105 +736,2024-01-12,Одежда,8,2724,21792 +1321,2024-02-14,Электроника,2,308831,617662 +1472,2024-01-17,Товары для дома,6,255771,1534626 +476,2024-01-03,Книги,6,187221,1123326 +473,2024-01-09,Электроника,1,499859,499859 +547,2024-02-10,Спорт,2,126741,253482 +54,2024-01-09,Книги,6,474701,2848206 +379,2024-02-28,Товары для дома,6,178728,1072368 +1345,2024-03-17,Товары для дома,8,30128,241024 +219,2024-01-20,Электроника,5,78223,391115 +385,2024-02-14,Книги,5,225399,1126995 +312,2024-02-13,Книги,8,421650,3373200 +561,2024-01-07,Электроника,4,298992,1195968 +1450,2024-01-12,Книги,8,79002,632016 +622,2024-03-02,Товары для дома,1,169661,169661 +843,2024-02-28,Спорт,4,355,1420 +1303,2024-01-08,Одежда,3,87211,261633 +653,2024-01-23,Спорт,3,281679,845037 +1200,2024-03-11,Книги,5,28208,141040 +1288,2024-02-18,Спорт,6,342715,2056290 +1390,2024-01-27,Одежда,6,219726,1318356 +378,2024-03-08,Спорт,7,112792,789544 +243,2024-01-23,Электроника,8,246678,1973424 +1092,2024-01-19,Товары для дома,2,165877,331754 +1142,2024-03-19,Одежда,1,199099,199099 +139,2024-03-19,Книги,8,445508,3564064 +651,2024-01-11,Электроника,3,357948,1073844 +1453,2024-02-12,Товары для дома,1,42061,42061 +1355,2024-03-18,Спорт,7,101988,713916 +298,2024-02-08,Спорт,8,104448,835584 +1469,2024-01-21,Книги,6,262102,1572612 +1323,2024-01-30,Книги,5,477147,2385735 +1073,2024-01-20,Товары для дома,1,271211,271211 +633,2024-03-28,Электроника,2,395701,791402 +283,2024-03-20,Товары для дома,5,35873,179365 +415,2024-03-05,Одежда,8,38898,311184 +1109,2024-01-17,Книги,3,110725,332175 +1401,2024-03-21,Спорт,6,50490,302940 +424,2024-03-08,Электроника,3,274071,822213 +270,2024-02-28,Одежда,4,489084,1956336 +1111,2024-03-22,Электроника,1,134108,134108 +920,2024-03-16,Книги,7,297702,2083914 +675,2024-03-31,Спорт,1,75682,75682 +640,2024-01-12,Электроника,8,471277,3770216 +874,2024-01-10,Электроника,2,8751,17502 +313,2024-01-10,Товары для дома,7,73798,516586 +1174,2024-03-22,Электроника,2,439074,878148 +1464,2024-01-15,Спорт,6,123715,742290 +855,2024-01-14,Одежда,6,54108,324648 +466,2024-02-08,Книги,4,63884,255536 +1067,2024-03-27,Электроника,7,272965,1910755 +783,2024-02-01,Товары для дома,3,270530,811590 +180,2024-01-14,Одежда,2,365530,731060 +282,2024-02-10,Спорт,1,328624,328624 +1348,2024-03-19,Книги,6,88858,533148 +700,2024-01-01,Товары для дома,4,216213,864852 +311,2024-01-22,Спорт,5,134727,673635 +462,2024-03-31,Спорт,1,245949,245949 +574,2024-03-31,Одежда,8,295135,2361080 +1137,2024-02-04,Спорт,8,438152,3505216 +61,2024-03-27,Книги,1,342599,342599 +793,2024-03-26,Спорт,6,452270,2713620 +528,2024-01-17,Электроника,1,226817,226817 +127,2024-03-05,Спорт,6,162155,972930 +565,2024-01-17,Спорт,6,50689,304134 +1027,2024-02-10,Книги,2,477524,955048 +484,2024-03-10,Одежда,1,248198,248198 +620,2024-03-06,Книги,7,171929,1203503 +728,2024-02-13,Электроника,7,317283,2220981 +721,2024-02-10,Товары для дома,3,8210,24630 +711,2024-02-17,Спорт,4,212876,851504 +1256,2024-02-12,Товары для дома,4,187244,748976 +322,2024-01-18,Книги,5,23775,118875 +806,2024-03-03,Товары для дома,7,71584,501088 +1004,2024-01-13,Спорт,8,26024,208192 +684,2024-03-02,Товары для дома,4,479431,1917724 +1271,2024-03-15,Спорт,4,303511,1214044 +1085,2024-02-23,Одежда,6,413187,2479122 +507,2024-03-08,Спорт,6,192388,1154328 +82,2024-02-03,Товары для дома,5,207506,1037530 +1415,2024-03-16,Спорт,7,273121,1911847 +1149,2024-02-14,Спорт,3,347976,1043928 +938,2024-01-17,Спорт,6,103879,623274 +1026,2024-01-26,Товары для дома,5,431261,2156305 +408,2024-01-23,Товары для дома,2,315831,631662 +382,2024-03-27,Одежда,8,42773,342184 +181,2024-03-13,Книги,6,410327,2461962 +1483,2024-02-28,Электроника,7,378,2646 +1223,2024-01-04,Электроника,6,477803,2866818 +993,2024-01-13,Спорт,4,434534,1738136 +647,2024-01-09,Спорт,1,489568,489568 +204,2024-02-04,Одежда,4,160759,643036 +1042,2024-01-30,Одежда,8,70457,563656 +780,2024-03-30,Одежда,2,237213,474426 +1484,2024-01-24,Книги,6,462911,2777466 +792,2024-01-26,Книги,5,239889,1199445 +600,2024-02-01,Электроника,4,26616,106464 +40,2024-01-20,Товары для дома,1,196039,196039 +221,2024-03-18,Электроника,4,312543,1250172 +1432,2024-02-22,Товары для дома,5,136214,681070 +1246,2024-01-02,Электроника,3,290207,870621 +796,2024-02-28,Товары для дома,5,323676,1618380 +137,2024-01-29,Товары для дома,3,422872,1268616 +953,2024-03-21,Электроника,1,420568,420568 +109,2024-03-26,Товары для дома,5,453019,2265095 +556,2024-03-15,Книги,1,185019,185019 +412,2024-03-21,Товары для дома,8,165748,1325984 +582,2024-01-03,Одежда,7,231232,1618624 +124,2024-03-07,Электроника,4,485268,1941072 +349,2024-03-23,Книги,8,16332,130656 +524,2024-02-22,Электроника,2,431667,863334 +90,2024-03-26,Электроника,5,428398,2141990 +1079,2024-03-26,Электроника,5,187956,939780 +1194,2024-01-08,Одежда,4,362071,1448284 +772,2024-02-03,Электроника,4,116393,465572 +38,2024-02-03,Товары для дома,2,262452,524904 +290,2024-01-22,Книги,7,91787,642509 +990,2024-01-07,Спорт,7,202343,1416401 +1124,2024-01-27,Спорт,6,360818,2164908 +530,2024-01-22,Одежда,4,84918,339672 +1072,2024-02-05,Одежда,4,136917,547668 +1120,2024-02-06,Книги,8,59776,478208 +418,2024-02-29,Электроника,1,304260,304260 +434,2024-03-26,Электроника,2,368486,736972 +1102,2024-01-29,Одежда,5,363607,1818035 +429,2024-02-06,Электроника,3,132119,396357 +680,2024-01-07,Спорт,1,140752,140752 +47,2024-02-03,Электроника,7,276654,1936578 +965,2024-03-30,Электроника,1,188106,188106 +922,2024-02-03,Одежда,7,446124,3122868 +1294,2024-01-22,Книги,5,120582,602910 +228,2024-01-21,Спорт,8,1403,11224 +704,2024-03-25,Книги,1,255777,255777 +29,2024-02-16,Товары для дома,8,114988,919904 +590,2024-01-29,Одежда,5,493610,2468050 +303,2024-02-06,Товары для дома,6,406712,2440272 +1272,2024-01-05,Одежда,8,289195,2313560 +498,2024-02-05,Книги,2,335267,670534 +112,2024-01-26,Спорт,6,428127,2568762 +1304,2024-03-07,Электроника,1,212576,212576 +176,2024-01-22,Электроника,2,317663,635326 +1402,2024-02-03,Одежда,5,189249,946245 +766,2024-03-15,Электроника,7,210138,1470966 +409,2024-01-23,Спорт,8,498752,3990016 +479,2024-03-23,Спорт,8,91798,734384 +92,2024-01-15,Книги,3,466466,1399398 +903,2024-01-16,Книги,3,263215,789645 +299,2024-01-14,Спорт,6,124365,746190 +1277,2024-03-25,Электроника,3,125243,375729 +906,2024-02-09,Книги,8,171600,1372800 +1263,2024-02-05,Одежда,3,440460,1321380 +717,2024-03-13,Книги,1,449819,449819 +347,2024-03-05,Электроника,1,116156,116156 +1360,2024-03-29,Спорт,8,232139,1857112 +50,2024-03-07,Книги,4,236709,946836 +1217,2024-02-07,Электроника,8,114529,916232 +706,2024-01-03,Одежда,5,277568,1387840 +657,2024-02-28,Товары для дома,5,181488,907440 +391,2024-02-11,Книги,8,62907,503256 +714,2024-02-21,Спорт,8,198844,1590752 +749,2024-02-02,Товары для дома,8,495045,3960360 +868,2024-02-20,Книги,4,154950,619800 +848,2024-02-20,Одежда,4,327997,1311988 +231,2024-03-30,Спорт,2,450682,901364 +184,2024-02-23,Спорт,2,431139,862278 +1180,2024-03-05,Спорт,7,462103,3234721 +1441,2024-02-24,Товары для дома,5,327850,1639250 +881,2024-03-06,Товары для дома,3,482830,1448490 +546,2024-02-21,Одежда,2,68560,137120 +147,2024-03-11,Товары для дома,8,233788,1870304 +497,2024-01-06,Одежда,7,381061,2667427 +505,2024-03-27,Одежда,6,235890,1415340 +1359,2024-03-06,Электроника,5,135106,675530 +1262,2024-02-01,Товары для дома,7,411913,2883391 +1150,2024-03-12,Электроника,1,467698,467698 +402,2024-02-25,Спорт,2,308739,617478 +1333,2024-03-11,Электроника,8,410931,3287448 +810,2024-01-29,Книги,5,153140,765700 +1384,2024-02-10,Книги,1,361345,361345 +406,2024-02-14,Товары для дома,4,184078,736312 +1146,2024-01-02,Электроника,4,369397,1477588 +985,2024-01-31,Одежда,3,181829,545487 +1422,2024-01-11,Спорт,5,343321,1716605 +268,2024-01-20,Электроника,8,234120,1872960 +1371,2024-01-26,Товары для дома,5,123135,615675 +1028,2024-02-19,Спорт,6,291696,1750176 +817,2024-01-05,Одежда,6,235790,1414740 +175,2024-02-29,Одежда,6,366722,2200332 +538,2024-03-24,Электроника,7,110525,773675 +818,2024-01-12,Книги,4,230200,920800 +1123,2024-02-07,Книги,8,84082,672656 +101,2024-02-17,Электроника,3,305403,916209 +1408,2024-03-19,Спорт,3,150221,450663 +975,2024-01-10,Спорт,2,195870,391740 +170,2024-01-03,Электроника,1,392705,392705 +689,2024-01-27,Одежда,7,194357,1360499 +271,2024-03-30,Электроника,7,125203,876421 +304,2024-01-29,Товары для дома,5,333772,1668860 +808,2024-03-28,Спорт,8,257806,2062448 +594,2024-02-20,Одежда,3,429066,1287198 +885,2024-01-15,Электроника,1,237698,237698 +1418,2024-01-27,Спорт,2,87510,175020 +185,2024-02-25,Спорт,3,189891,569673 +1456,2024-02-02,Спорт,1,428475,428475 +1179,2024-01-17,Спорт,6,54293,325758 +1219,2024-03-26,Спорт,4,181408,725632 +913,2024-02-12,Спорт,5,767,3835 +805,2024-03-20,Одежда,1,28108,28108 +104,2024-01-27,Товары для дома,2,357600,715200 +314,2024-03-12,Книги,7,191772,1342404 +453,2024-02-06,Товары для дома,5,43975,219875 +1029,2024-02-05,Спорт,1,272467,272467 +670,2024-03-21,Спорт,8,355861,2846888 +307,2024-02-26,Электроника,6,17493,104958 +1157,2024-03-14,Книги,8,234933,1879464 +1106,2024-02-25,Товары для дома,6,465555,2793330 +654,2024-01-29,Книги,1,437687,437687 +85,2024-01-10,Товары для дома,5,281876,1409380 +1074,2024-03-17,Одежда,3,211864,635592 +625,2024-02-03,Одежда,4,342719,1370876 +111,2024-01-05,Спорт,4,450151,1800604 +784,2024-02-12,Спорт,8,293523,2348184 +1295,2024-01-28,Товары для дома,3,78770,236310 +1299,2024-01-27,Товары для дома,7,309745,2168215 +24,2024-02-04,Товары для дома,6,34702,208212 +1234,2024-03-14,Товары для дома,5,430766,2153830 +1337,2024-01-30,Товары для дома,2,234145,468290 +465,2024-01-15,Одежда,4,406938,1627752 +247,2024-02-11,Книги,3,351343,1054029 +854,2024-01-10,Спорт,2,120035,240070 +890,2024-01-16,Книги,6,404452,2426712 +713,2024-03-24,Книги,2,449955,899910 +685,2024-02-20,Товары для дома,6,479790,2878740 +115,2024-02-12,Книги,5,146069,730345 +161,2024-03-03,Спорт,6,15218,91308 +782,2024-02-13,Книги,3,339723,1019169 +1383,2024-01-16,Электроника,8,366082,2928656 +77,2024-01-09,Книги,4,311970,1247880 +1394,2024-03-12,Спорт,4,226608,906432 +1316,2024-03-09,Книги,2,263890,527780 +1220,2024-03-23,Электроника,4,321757,1287028 +196,2024-01-11,Спорт,8,126541,1012328 +1468,2024-02-17,Книги,4,404120,1616480 +1000,2024-03-18,Спорт,3,466487,1399461 +355,2024-02-28,Электроника,7,265055,1855385 +989,2024-02-02,Книги,1,412626,412626 +1446,2024-01-25,Книги,3,168110,504330 +159,2024-03-09,Электроника,4,391914,1567656 +446,2024-03-09,Одежда,8,125394,1003152 +1166,2024-01-13,Товары для дома,1,398103,398103 +819,2024-01-27,Электроника,6,425042,2550252 +1409,2024-01-22,Одежда,7,335849,2350943 +189,2024-02-11,Товары для дома,2,446543,893086 +1419,2024-01-13,Спорт,1,33446,33446 +525,2024-01-17,Книги,8,166214,1329712 +478,2024-01-18,Одежда,6,23245,139470 +512,2024-01-28,Одежда,8,320800,2566400 +1193,2024-01-21,Одежда,3,150270,450810 +752,2024-02-20,Электроника,7,174178,1219246 +543,2024-02-26,Спорт,8,217906,1743248 +284,2024-01-30,Книги,7,391521,2740647 +320,2024-03-19,Книги,8,116061,928488 +729,2024-02-11,Одежда,8,15533,124264 +943,2024-01-07,Электроника,7,88075,616525 +78,2024-02-21,Электроника,4,62856,251424 +194,2024-02-03,Одежда,5,178436,892180 +317,2024-03-22,Одежда,2,492984,985968 +1171,2024-01-16,Спорт,4,487702,1950808 +1169,2024-03-04,Спорт,2,73636,147272 +1140,2024-01-14,Электроника,8,218119,1744952 +1048,2024-01-18,Электроника,1,409216,409216 +1134,2024-02-15,Спорт,5,468991,2344955 +566,2024-02-13,Одежда,3,292465,877395 +1413,2024-03-31,Электроника,7,140233,981631 +45,2024-03-09,Товары для дома,3,401518,1204554 +645,2024-03-15,Книги,7,38289,268023 +440,2024-03-25,Электроника,3,176562,529686 +455,2024-02-25,Товары для дома,8,48085,384680 +616,2024-01-21,Спорт,5,383318,1916590 +619,2024-03-19,Спорт,7,448868,3142076 +277,2024-03-08,Спорт,1,477334,477334 +1061,2024-03-28,Спорт,3,4666,13998 +34,2024-03-11,Книги,2,451297,902594 +1221,2024-01-06,Одежда,7,357854,2504978 +583,2024-01-20,Товары для дома,7,216511,1515577 +71,2024-02-28,Спорт,8,149553,1196424 +814,2024-03-10,Книги,8,431286,3450288 +917,2024-03-07,Одежда,8,216561,1732488 +927,2024-02-29,Спорт,2,164644,329288 +738,2024-01-17,Товары для дома,7,45769,320383 +521,2024-02-29,Электроника,3,421351,1264053 +1447,2024-01-07,Книги,3,280479,841437 +769,2024-01-22,Электроника,1,339215,339215 +439,2024-02-07,Книги,1,442724,442724 +1118,2024-03-20,Товары для дома,7,317527,2222689 +1154,2024-02-05,Электроника,4,26399,105596 +493,2024-02-11,Книги,6,53791,322746 +1247,2024-01-16,Книги,7,21902,153314 +663,2024-02-26,Электроника,4,122862,491448 +882,2024-03-09,Спорт,2,171312,342624 +1297,2024-02-23,Одежда,2,425289,850578 +845,2024-01-21,Одежда,2,458450,916900 +762,2024-02-07,Книги,7,435832,3050824 +665,2024-01-30,Электроника,6,427707,2566242 +1458,2024-02-26,Книги,4,129585,518340 +646,2024-02-14,Книги,1,367204,367204 +722,2024-02-20,Книги,5,486998,2434990 +908,2024-03-13,Одежда,4,411308,1645232 +1229,2024-03-28,Книги,4,222408,889632 +1094,2024-03-22,Книги,8,30416,243328 +324,2024-03-09,Спорт,8,71128,569024 +1347,2024-01-25,Электроника,4,17621,70484 +692,2024-02-07,Товары для дома,6,79908,479448 +1034,2024-03-09,Одежда,7,461445,3230115 +823,2024-03-17,Товары для дома,6,282470,1694820 +1127,2024-01-20,Книги,2,497784,995568 +370,2024-01-14,Электроника,6,183561,1101366 +342,2024-01-02,Товары для дома,6,187823,1126938 +214,2024-01-14,Книги,5,457557,2287785 +875,2024-01-02,Товары для дома,1,137461,137461 +1363,2024-03-02,Одежда,2,60959,121918 +1439,2024-02-20,Товары для дома,7,131018,917126 +940,2024-01-10,Книги,4,11430,45720 +1382,2024-02-20,Товары для дома,8,451098,3608784 +734,2024-02-04,Спорт,3,80857,242571 +1181,2024-03-18,Товары для дома,5,480201,2401005 +1308,2024-03-17,Электроника,3,74823,224469 +217,2024-01-15,Книги,7,431026,3017182 +851,2024-01-17,Товары для дома,8,311260,2490080 +1473,2024-03-12,Одежда,8,413434,3307472 +1144,2024-03-03,Спорт,8,59212,473696 +367,2024-02-06,Одежда,6,314788,1888728 +1281,2024-01-29,Спорт,4,399231,1596924 +1168,2024-03-30,Книги,3,55744,167232 +510,2024-03-07,Электроника,2,202893,405786 +1346,2024-02-26,Товары для дома,5,5616,28080 +1078,2024-02-13,Товары для дома,8,380922,3047376 +396,2024-03-14,Электроника,7,225069,1575483 +389,2024-01-01,Одежда,4,107177,428708 +790,2024-02-05,Книги,2,394436,788872 +1089,2024-03-28,Электроника,5,200105,1000525 +474,2024-02-19,Спорт,1,457878,457878 +208,2024-03-16,Электроника,5,398568,1992840 +199,2024-01-03,Одежда,4,48787,195148 +1064,2024-03-31,Одежда,7,336982,2358874 +443,2024-02-26,Спорт,6,22908,137448 +160,2024-03-03,Одежда,7,115041,805287 +623,2024-02-03,Товары для дома,8,201104,1608832 +145,2024-02-28,Спорт,6,69909,419454 +84,2024-02-28,Электроника,2,325667,651334 +1084,2024-01-29,Товары для дома,5,186271,931355 +545,2024-02-10,Одежда,6,451667,2710002 +1264,2024-03-27,Одежда,8,384289,3074312 +120,2024-03-17,Одежда,6,227837,1367022 +1451,2024-01-28,Спорт,5,179261,896305 +756,2024-02-10,Спорт,6,93134,558804 +852,2024-01-02,Одежда,2,4228,8456 +1143,2024-03-28,Товары для дома,8,461348,3690784 diff --git a/outputs/orders.db b/outputs/orders.db new file mode 100644 index 0000000000000000000000000000000000000000..a47ff2f631dcb9ea9ec2355d101a794127b71289 GIT binary patch literal 102400 zcmeFaXOtC1&@epHVPDp7I} zK~WY&K~w|<6a#`0QQ@n-bE|I8vUhx*_nhy%KVJ8=0k%?CS6AwunFsD~(SKO)v_1oe zJl1_!S`{r$({-&uTAHS54F1Uv|KLx~p9TH_{;MnhAM1aamN6|c0KaA4$(sKn{OiA; z|1|KQ2L98)e;W8t1OI8@KMnk+f&Vn1X%jj#Go@xteaijAy7zdrcdzdKA05@TXZK;f z`wkp3s_T&6BYF=Q9^-F$qt;CtwrP^qrs16}nxy58nO4S|20sIb^y)pNYcC+1)}~2^ zHfgQyg@4+%Xpz>aS(8ThM1XPtAMHJ$@34MlqVQ$Y>ZVoBOl#Pxu}Y*~-L%q~nVFR< zhDYfzj~w(|V9g%@v4-_l$W=%yT|N{3a@5e$Wy4ryD}?`pGtOJQVWS519@wW00_Dh5 zdRXs~!%Bx4Mr0l~r2k`4kg{p@(lR5&?b-AkIDEjcwC1haG`Xuu>)SLCVWEJAx%3|Z zE75z1%}DvBLOrrZT^|`ZsCUmthW;CeT;R8J$pxTry03NfmJM5XOuMH^$25mdNip8C zY3-Z0X?AbhHfgQzZQs1{q*UEZ$)8`J;R{<=cmhN1e=~>m*nj7+mj1nHDk|gLrsGgt z|6aGx$JQE9%e^4~ubSiF;oS!e>pyH1sW*m75$<-C;%^j{4j<5eSl2;A`uFVpKQ+YL zF>YscJB-3Ix1q+`TI3xfrjiTqcCNVqa##|L91oNG_jS`qA?4C;7uohRxwi%jK+W$T zCm{$WhKdJA_^$`=3N-YO3w-V071$gY9eg+VQfPLlUFiMbpT>0aKJP+np}Zyj@uvEW z!0+03dNtOQ<+pw{-eC1StpjU~KKz?tVbcs=53tZNy^rNJmw0=yKfLEd6FueqBV=*; zv}dumUT~2(9cXJ+7HCf9hRVrpy&t8jISvX=wzH?udwyr-vu z#5<19%K6Xk?42MBd+E`{U%Hh7w45nww~%(`9qJspzVw3lY8|O-BZ+)RR9#Z8eX~%f zCvt#F>Wt~{Bdx5ODlJxX$Iubga^&=YwpJlf<;rey3eWv8aCUMo@pr}Ie3s9r;ZDn!o_`DW5W%VId! zSaePOrT)G)Usi*K&RN9HC`VQ`H{D3>WGRup8^zc5;4DG!c^aT8W(A90?t$9W|0X_F z-S{w8YrhyiA-r@t21(_Iazt->d_s<%>@a`hif8`J_ZE^?UUcIc&{D>OT?k- z_`3)Mo84`jne!Xfc{3Gh%Skl7s!`g8ng3R~#W#rdQJf4oE*IJc+kP&ta|5EilF({I z_ol_}PmQ0l7lHId0;&=ffEhPC1peMw3HD~qoV_^=r3ACi(~yk)=V740@+1*;w$C>2FQqcygQV~`|alX9Vi!jji^+QN1>yEr7=4QS4 zq_?XhZxK-zxJhM^O)+L>(b1ok0N%xbH=Bd=0^SrH%rPfm5TTz@KG@p?!$tp(0(D2B zdFpo~A(*K$2}6!RZlKRLK=7R-Lau!)5@NkZeCG|ob<;-0~JsGKIx<(x)iZ-?C&A?@oFCiKzI8Q?} z`8{=0f@^U_^Z_{eEM)_mlLx^-S+wIw)O~A8>;xt4QYob!azE_FT%h?2*xlA6)Lx84Fc)U5;JA{8@%qggu#9S5_th}{)XR| zkWPAw%=WfjH1mEr^L|`4`KV0_79p0~xH)}Ev!-#Bc1A*(Vk+&7{ z*Jr`Nl#oM82wA)bZG@FVd~k;@E{pRH9lRb3P<@1Y3gvV60gR6+Yus!Ns0O0y7$`zWk3Kkj2*8RzXxvJAd3m^8l)>~3J=MG4tcq+oXm#XU*>^Yw#+w6Zx8{%ej8 zJWQO5J{Tp+%8WWbAsgIE;(rIPYDUSNnM?E?+FqQwniCkc4(r`E0$d2miiiP%8+3%q z3nx?N-Uom|1mvG1LDf?eBxXb9I*KAi=Bq@@arUwG3M10|1<;C z0J;Dfu?jG!7%o7{>H`YIl?or~haLf3Er00q(2mf;&?BL^;FrP8!54y$2RjAJ2lc@D zz=6QrK>xr!fpP)A{|oV?~mSH-nri4-nQO5 zyr$<1&mPY*&tT78p0XaV^@Fw3nqv*K+E{m3rul`r$9&m*#=PGwZF-E$#{0%%W3cgn zQN>7-7v&DQL_Q_E$_y#QC2>fs5hFz_ktyQ%FZ=*sz@Oxuc|9Iv7uX@TicMi1SO$yJ zuj(iC<@!jylU`FVsC}O^Ddne<%&D|&m4@B2i%MC-Z^sJDoDy7tr-YT=`SsUn5_Sbe z0%xjZY4cYl-G&}@ngz_e%E}yrBH}T+0j#{YM=r75Q@LKCwh*$RxDy zGf^(bKFGYFv6H9FrgmW5iCjXvX5+kO+3mUb)`$u%C;gR6Xh+T`I<-6C)HKLNLi6-q z({pJ$Mqwsuln&(*+BN?ct=BZn#aC_bl}NpnOKN97tMHw7--b<6%X&Y3kxS|r`7^6G zp-pCv3yH2ub+;TvXfK`~pNp|l!H8~F|01v%74xaCT1bThJ>b{H9Nb81Q=7KuVlJ^` zL?qsQ%d}j|cI_~+YNPMVCACs6v-Cf|%cX2bjV>Rqz2P=&5?l6I%X3K`BRW}6^cs~* zYS(;)Ramd(;;VF9SiZqSb4l%J-Wf#()V>Xyq!#yW-k(eA7`;N4FYD1}qAIv>xwI9*8*xp=HXXWig_){elb4i`$YS_J+x60*1vZ6jD zQ19(rLOZ(%#oj-cYsyMlCz~$$CzsH%B4ec{xnhiaQ<()rlXLM^BBRl-Z~a`G(NPp@ zi#OheO!mRET7I5O=vaX<@%PiYH0>G~jm}Fi1s#gcy#PN_0u1U^cU)eg5O7_t~a(_E~#ULKH1^!w{uDD z8u>(xJ#BMItwcW7;y}GzQaeLm-Q~~RhD}n-{*!9vk~&7{;~B5Nl}l>(&=+^&P%geo z=re{NO3Nj+BlO9phlkyUO;WQej~6QgX+|^x!GTzwX-3IwX}N@UjeNYy_t%^b0tl0V z1b$A>C9@;$$u4u!bIGh6)3Nl|i{{dFjJU_*3)RbjaIMVFHSXnqIV~4kCG3d~3-&q_ z{#?bjHgQ_H+t8z$HhvtLOX?VLkGCJ&DVM5U>0UbN%6T)Qb(=z>x-Rh7I-&Ot<;`;FHg`!qnO zs9JzZUh!A*-u6`iB1sh&nuv-gP5gN*03#%u9p z{it>U=BHtIauAi$Ij#ne7U?7jG~=@J+(;V`-~Ddv^0cyPgW5g+&2{0$eL4o zFFohvJ9?mgdusz_YlE`IYAZ8wy@cm#Q{;P>0#AX*V$CYYH=Kenbn>sB88G9k^MQBv zBTVGX09uYp3^L5hMaq}jgfM-Gmoi7GOD^+=s^*;T!}&xn8wUEqu6AhFt`DPF&Y=ce zs_2PGj)RYc4@)mW);(+pXl5z7Y~*$b8bf!4aX(#`Y;9Vg{nB*c4J9e>hP<7PE#7l9 z3}oNc1_HmMr0~qFS3EenFw-|RjzI)#==F#)IH~{LZ3(oZ zPBf_)d5$!u4oG{wR7Os>7nINu;bXOojA7ScAo&hBiC8Ca(pWpbSjSnYn)V3qJb>fu z*Y~Zn-4Uvt4Hdr9r2202@%w{Umg51~14s)t2yHYrc?t~FS>$L2R?9VVOI~hH=;Rq> ze?JliEQP($mp@=kZGlt2523PRihq@I=05DK2_*g>9a0P%JM8 z1NGAk!JVO1=o7v(64u~WZfZk?PjJZ}N%2T>3eL6(Lcmrgjc~I@)uc7F-5V2(l9mYm z)q>EpZn(;gP#$m^F20|e{i`O|UV`T1a(;>eHYDasl40q$7Ki>mjm#SmbJtQ#@@^vT zTq0uCN6PLV%F?HF_cyXo@%0c36s8y^lOOf)tvZMkt7}7n<5hx`taTR*1gS%Wl+2ko zzX}8AUfTwNJ*Z@{hIVLzSe=S6wU86cf|ghq!}sMsB@m`2!c&C=_H6!8A`To zLtt?q6t)Dx#IOlzCi+YCs)O*68=DZ5V&uP)?|v?R+s7zF8q!ylY--~Q@@IFU0*cx& zkf6D0*_4u(D3OGe>FS6h@iTm<{V5xfa$%ctI5TxwKTF?NA?WFbb1XzM$FO6QKQ=Js zrU&5*qWrNAprrn1s^^Q5C{+QZ4|#x#RFbdV5#MPw&Nn}DQ7c?i)@z@>iP9kV3)x61 za*-o^{e+^ZU<-A&SaGF<9o)}$ydVrgZCZpEN@qDZEv#PT|S|2^<4Ap@J#pgfgXX^x@hfX&8#I> zZ!5#{u#xO9^P;)eoMrYi8<~ZS-`OXugz=6s&*-U_gFZn(mKIm_B01H6&QIiO3!3Z` zsG(R%yD+md3mx7ou4+Cw3Fq2ZrO+}SwNc@5E=QNl)Cacp`X0b5G}QMZMm=SwpBJWZEpmJwAoHK{#B@3js$#ZaW9 zx)aH2J?~2=hdR)PfvGD#R~Tpe796z%FS2Ock&x<`IlFkkdZRhs0MlM0N-;_Sc~ggh zS6;N&iKt^c8gjw7VsrhZ^tm<|cxP9oTl~2?g{Gb(k+%_bMLo=zS0YfRDXq*#6dCqM zo-4z|=`THR>_!tCMMPtGQ6@f}=y}VF3-CC}u5<_(E4p6P?}WBD0%dU89@l=T$queX z&cl%sq_cTSY8ZP?lzI9Ggdc{ILc*CRyeW(AFY!YwbT2~`DO~)wDeu~w{(A$&8jM`r zeWfsFk0{XaG-_oK@>1{h8pf2arL$@wOyurwxWPf5%QRZdsE~3Jxj$yp0iW-hd`jc; z;^MP&Zl3kZ={jkLQE13zT&61Jl*0wreoF>*h`1>RWyv=_tN83`G*(>Gkq8SJf|9Hm zeAGXQpIxCHuoS_ZCAO*W>+Wy98mH;jCQ}~rF^xVID!gA6u^vX+?g@yHH-Ad`YbWi9 zJvLf6M&@ld_G2ZamfeWp@E>O2`9js(5Y?Rs6zgFX$w!CsJ$erz>_F*b`Etv6Jgds~ z*@W;mafq=qrQUCc>06DrbhWL>0pwPeNM=-kK`XR{pd3Dm@yA*lXQFrcHzOFtf3jA? zxbsxW=e$H~lMMv5q$9{MIrogO^d_3gTL>1bnH0IsO)K!GjR3i}au{oh#dXr^tqeyC zXlQ9~5LKniz@B0-h|mUv0js512!7<1gyz}>7v_Rv zMS9jDvDeyYknC2Cilo0^4F-w*D#AeONn%?}td1*LgMii`kXn~X_Ey!vSV2OrCLq@? zM&xliqP+^yz`98QsSm4UHvXP~Ua^5-^_9Yq%k)m6$AT0>R}!Td_Xxz!DlqU8wYGxb z-Mh=3Ynq+unI~$1U4VRV8<)63+<(i?1{Z3 z#PcXS9J{#4F8R6P2|bz<+B~A}j>h6odLN<(T(vob7Nccuic4FI->Va!*){?slCFH1 z7(U1PKAq5J5g%8_VCj1^gZfx9&u0-0$|2fwOwXvr9vntMGi{(M6{{$hXG|X7D`{*r z;>|!xu{zkoOg>hqa~+~O9jQWWBG#61v~l$wX=KIIY@l#O;j&oPL#xvSmH3u@-s7HdQ z$05wq2m|?8RCG4(8~?N85#}l6<~VfZLt7@k^&uwqqmd45vpf?tVfLL@_@(>Opl?vj z!`PEZ6OQUg`JKM)^sN^X;YK>TNW}(%3tL%`H~zZo5@u1i#RHthg$^OLeGgop@%~?L-E1S!##qo z!Ae0Za3ZiS@MPfbK*@l{FZ)09Z}rdiKkBdTm%ekp?Y?=wp1!)iRPQg|qu$lt5#A== zG|yk2_e6cqLeCHp^tAGnwSKntSxfjk`gQ#yeZ4+HzgI7#eH4Cpnnf~gSg?}mCdM4S zB`OKlmXw6MOpo?}UF!zJsJg9W9eBXR9G25A(C@K{!j^Vk5aX44`FG7mllhm&KS_wl zX%i&c?m|FMF{#6VaM}v3W4#&j(cUF-oab}e?z!wn3)pBZO@!|n5K7-rl%xpmVTvWXh^>dNPcQUpHMrX(9Tn{BJuqPqNT)s8$8?+ zSF|D7b`f|nk+iW7S-U?-X7EeTr1Ui~6VoHTO>oW1T_LmCd>AyVKTrbIdvf{Uz__HA zXfJvQX9Y1c&smxJ<%B@jiG<)Mfny+8e9n|Y^BRyC-zXf&BQfLL6M?R zDUqmthCmRF@|>I0E6R7qo@1XA*!wnExLvEbIg7nABB}gF0(&oS zFjLfTQ+P)U)PU<7EN~U|1e_48be^kd=v1TIT5}km7J-42*Mmq1`umEGggIh#;ZLv9yaEUovxm#poQi+( zJR$fH0fIoDim;5gN>^J*T@l@DBZP0!kgt%eL*IH<*oM19`wQ8qT`=v({xE1-HxS0TJEXR$BcHg7Nd2ks zrfHe8_QOCmYS)nzq<;h>`8|QS#~TvR??_0!zhkh&OXJ?!OF+LN5a@>}!2_ss17;~) zX6;vG7t0Zu`p`GLWls^pFE#?ypfRGV#ShFcQfMQZoAxt_;XGKF)6|&Ll-h#VkSv&+ z%VKIfyf8@bS5bP1Hi{`rd9F?2?kg!1_=&(`6cpOZJuryu6%-j9qC(cj$J2^QMOU=WOBM+L2j*ZzDi5LHuef?Ca*M?MwE4$sYD@@J`kj zczb%Y^gZ5y=d$OZKGZYU^PuMrPd@96^_Dfmy3>j`zc=4Dr<$$J;>P#JCS#Uf$LMb~ zHj2s{@;$jij**>YH5n(qg!}& zH`>ZCZju%rMIZ<=d0L(E#A$Xuj@I=N8y?i`*xp=w=ODX3n)*IW6H=5FdHWFw*dKw^ z*v{nBFM9u}MGX59Lq}3%u(5%V){1ELB{1b2&5)loC?TU+SRVvZFT|S0OV4Js{fd^b zHv+*7UE+_)mmJC8d<+TD%SHodtq35D4vq46_tQG}K-#hDVJY4nk#eyWA#_Is@TPe$ zkGQ$G@E^-bjBYjpR4~eodahS`kI#CDfVv`8ungKzhBkjZpG+^8(H|lprCn|D{=8r_ zyI{!KL|u>_1RJ7c)jz7=q!)JT4-$;SWGqqsr(#`4qW{x7BUr4d>hJ7?L6hi2@X91C zvFBvTn@b6(qYacR{pZIzCx2d?fI1+MdL@#{pS-@aiI}|T?Gea%-9hj5ISeAz7KH-i zA$@S;%2SE&KTa0b27%n;I=r8>y9Dn&r$2}rpDZ|E04@b&nR z1iS}<{;&4fZ6U%|qH3v;uKNYe=PnxxPSKV5nA&?s<@9-E2~80QG~;4$ro39d>~j@q zVVj@?u@=^pUCNZ4kxIfeLOzi3)20#HkH`7e#^H#U<7w`+fx@TQ1SB8)QqS&8gc>3t zwSB?Z!(WS!50QBF5hzyo&@kh_D>oP(7mGAS>Jfs{>D14D34@ltjtvveJ`}B+?B}zI zE2-qvYujMpj$%Yx#tOeEYS*GAsEG*fuENyQnwsaMFCVOd;;6yMG6u$189AG@bqCT` zt3t_wcX{vXNfWDX13^4-6hP8sH%kP6CpoJjLx=+|ro#2UTf`m3iF#EO0Zc_vo1tx6 zARdTHnuS6@9S~i6S$=c=GgC=~$^_(ogm3sB^CzDnv`Q#BG%H*rkDRBG@-mQ{Q^ViC zdPkRL6f-I!5V#^`diEP(3914@LGq_Su`a*BAco~gPUVcm(idp{y&CDWERu3&-SA4_ ze+riVmcYs&E$5vLY0f%b@)(_M>7|L9yGBLVf!6M`SheY;2u*RQGNFFA+BBJx1fnz~ zB(q9+%j~9=Nk%=4vcaOr4$LlU(riI%|DTJPu=(HkyJ!plW4T7)FEVN{;UnuK%_7w9v88n$XBl z>rnaN@4@52b-~HO`+{WyzXXm3RtE;boBs;DljD?CIsH?+IF8SgWjOtOu=XRzC9wbEi4o>|-`Geel%(X5(3- zpV82WlV8dWa;oel>q@`)M(h=fMK93+p7lS?S8G2(t$zI*w+k(Q^4c8>Vta=<1Sb89e#R_^GvM(T*Tc zteY4HFMln;q$_p$VdM;6im00A;3ZWH(&>!;E&_qWbK85`j*sQpH6+X-LW^-NB=Syd zvgUUX!QE*~ZSA|f)7NBp2W_tC~#OnxtNhUS4{@}^NbyL@tVzwIIBF%n#hU2C5* zjb8k$?AB+C{O z-u1+d>G^lEDkEvlHxrr?u?5@lrT3@NwC0--$XQl$c4?9I)`vvvEgKBnw{m`D$S(QQ zGUn6d-z1|bceSGzf67x3@0h&LG!GTf-d%O=2^Nj?i=t%jLM$Q*M^w({m@MUMR z9?qWZY!1ms5^f-%7@>k|tG?HN-A4%P5dk)Op2ZwzBE|4GA%t~^5UZbMYWrr&yFVix zthEt9vyM2!WX0FLogbo5{2J1AhGHYDAPge*DndcUq$t#6e=SNpU!8ML;W&zk2e;#i?L$ zVmX@C3IvMvl#ei*>@1vol`8e+gb=G`uyTS}If0~DhVW|6WNI-s4NrSO>nd<6!9 zKnn8lMoUBgFrAj^Wg8}Za;z+qrM>X8*b{Y#FCi&#+EG$sN9{sAdyr5s+Ca_@ljM6l z#qZls9%KnJ1S50tW)_<~EV1@d(&%DBi_z0I%wB6NJje)P5h6e;nCEtheAtJiUx?DH ze#J7EG^q0xKB36<1qzUh^h_Mz>RB;>wEP01IqMpsm;YY8zK(P=-v$di4j1Zz9Si#E zL{I;px6xn?l>|ESIV7Sz4@Gcq$20a?nruTyUHV)U36f>SJ`CgcPs$#NHc{pfm=e^P z*up)J8l>Up6d*DpVeA`M(6C5Vvuz-7LXHT{%+7BFxAvgron?cCYm^wv+rLniX6K0c zvxoqt2rS`wltp>|#q_};eFg%>I-xN6z>2BfXo)u+Swmn`Sg)U#oG%(8 zry&q@7YNAY6{{xKp@(+#smK~Si!KIY$Yn)~9eSJAeu|A2KB;g)Gxfe7c|M7{+R2Ef zUYxMB-*%YmPt$r$BDo!Bq0%U<7kN$+*hB<#)-doEnpcf!bSSM)KrmSSJeQT19SehE z(RdpkOy9{p{A~*|mT?Fb%N<+tvFYU>?LfxzjE&%YTuJglkLSyxr-=2j2;|=AVXV?n z@z5orJ%)r)wo2qnMWn8$3CPh6vb5Dnvc?*Ub5Ge|;Bj43L%rTI7({$D3JzAJ>}e+7 z`Peu8HL{u~5e$wIU984nZMcS$OY% zWxvmN!MDpd-#6IT!dKAyyLXRw5xo1amAAB4^L*yn;u-6?*Hg~Jt&gmA)?}-PRo?tn z`@#IcTxAY4?>0*qKN~xY36M;bmcPs6a-Doqwv#2rui~JXDf)^N_ZNo;PEWu3YR4#E?yri@r30tRxx5h8)_>Q^~YF zp&oTfb4fNDn4lvRFsb>yS}IXbBrw;!S~9(!*P!}~CD>@;NS9~8mFB#mB`?({apIAW zv-%VIJzHc3wVvTU>i8W`*RupEN+u+3?~1;Z#SvO8GajMy5jw4G=wIPYBQ7aElMsS7 z0+@Y_1jCSnzDRo|gDf(jaEMwYo7yz-?kH71QH@c|Gh=?0K!rX;)rSb`#UYbd8kpR| zLqJ{|2zqqN1B%RyzZxt_XUEKglwwVY8;^aH(0ntwGz+PMvr=4|QSD>>&YNUTrVSNt z>$w=KFxr*Q-(d-%87PhWIVltQezHoOB{Yd>kTbY&4J^jigkWcdZL)HrO&{L6|gB!kp{wt>Po8Azv07GB}4O`lWMuc5%e zU!A=Cs6{Mr9#L$ubTYP3(q5c}l^%H`@?I~JoE_c0~uV!1Kbp?U49I33ux{Qkd z{xH${(FTJcqaMR(CyI(6qDATt2n4iT)F;L9ld1XBiT3w48iYsX9Foc7`FzWZqodHj zL)x+KVMw#rKk3(_hZL6yK`A{f`zxo!`db8ooQ70n%AZ@5U7AQL`iA6lu8Pq+2p@6KSS?MWVUeb(<`sO%{e3{X7zPx>|A19zBCzC!(K2LEXE7OdozP`|c&u z{Fj90Se`!feO2u{_Bq#N&Z694!OHZEP9Lze=yAdq2<12;lwag4kwM{F{~UoF9US&q z+k7Q%k~%*lp&UmDlBc!{joN@Ij{Ygpis4txrE_7>Tu&oBl$W&k4SC=4qF)~+hkgoq zgR^qkJSICaCt=@BDz!dA+G?rA+T?uTl=jZYNE((XPd_L`(Wm2{vLD!kSJdbyk*J#6 zXkU9_5Ydlp7)Zlnb!TOvxn(XaAT69g1hqFWv_EI?OPRC+$B}dH%DUR3)KB^m^K1l* zb?wO%J%25-V;$M@F+>0#qgawC^#goXhLriC4FzwhP}~9Ey9)+Q;{&7wk%wFcXZK7o zzFGj~@Etj|>i_Z^lwO_+@BiDQ@iOc@+sPKN?*4Nullk-u`W`rG?;EJ2Ar9mQO*+Aem9S)s|$8_rq zojwYyRE14Om45D9?>;@!w_?UDu7YTHZ#0^v^Xy3%;g*aGCwes+=B5IYLt$m|1D0 z-l7>zzAV8g-3ZBddgIq+5&tqa5M@!iBF`>3Rz~1BP(GnYg=Gq8$yUQTp^W-@h~?t z+f59vCojs>R%_lf;d8Df4PHeYB5hYlA7Y5a49{kN!oxImYQef6I0)n6r}Dr0EAgSG zY;5=b;=Bq!ET#32G-RDUBtx(Hw%O@H5@t9WiF=Ua`oWg6#W#d@7nzOgeJ_)@+>??< zZ`WeIan;pl4lUO7NPP8XG|^rN6l;x{n4alL?uJ1EKMCQyWMT3-Fi06akSN3_azor` zxhMW|UChc@cbb)}QS$a5!yv3~HWnCwYo}7Ya1sUy)D;DCxD#3K18>_!iv~nks>7SqB+c%Llw6}p^1IK7g3h~3`gtu0b&e|c>T(?f- za|hx!Hz($8P(q+fI)jp>Tl#P3FiBw#Ads_yVC_n4>*y&Oc0WPIXoZ^EpNou-q7B0P zP{dgGv?Y75Q{b2VB<#J2pr%2FzGj@~7y9HiYiR?8UAbZ`QonxA^Eo{)!&)FMXB}g) zkDpIow}x2WV}peY8PboT_t;?Fmqzy=HF^~$=6wU5CdV)com zqfG;!r|Kgw9Hp7mC7v;C)nXejCQU9w2z8KdtWrht^h2SoX9=M;iVJ=w&vi4*p+hQc zq8l2l7K#MAa`7t%tN8LIU4` zgks&cG{x~xi|zc05UL`{ShWt5gNJ*+qUR-8UmGEOmPM9n=+n-78a55QqLt2hg%&H0 zK%i)4nVEekMbmCY(mGmA(wtJRhBT%%+w54ve8)9VwS*lkh{4rCMl9{jLH=&v67a1ce88KV36m146(qn zU9h-zpcA`0NYi^1(bUw$WG^p_?^20qKa4=oMs}kudsmFBG?^l5e;W;glw-QG(5Kq$ zy0pXkAQbHFJWb9rKK!%#+?e4_Sef%u{L107r2q;Y>smqNl+)|q z0q6fGn17o80e^Ad_r62ErM@TO_P@?L`x^U-dT)4-c$a&h(wlf&c$4(a@ZSD?o+X|q zJZ*#RJn6xb)<4!EYpFF*?{Af~H1mi##~ffbhv)kLF^;l3jK#(V{H-Uk5%93<%T>82)pbhWl1Vf>t;mSWo-lFsi`$$_b`_IE%knglynlRH$0E3toSQ z|7Iou9YI=Z8;u!XtO)FA`rY5;WS+IbKoI53%~-z`29bJ+NGblnk^_>;4_ZUAzd?i? z4PBG{Q7v)*P%_QuY%nke*OXPVgI5Em>9tF2KT>zPOeyL#NUGR?X0w+hRa_?jrWg!@ zSwp0h@XtzS!yuT+1f$%CH%E4ZK{Hv0yxe;(!o2U@!i@@%G7s5kkh>`zF~&-a7EQ0y z9(xD*Lr$6J9+UdiM00&FqIwV!)clH@9m*wJPZQ7q1Og?JU*|$hgU_4N)c4sy;LVh& zi~jGxAo2DPp;#_JTx(N$TD08VjR>&n#MuzO-KkB7kssZKK<>4-T+W03@_U=>XTm~Acw+) zeyyAN&RC+g(guS>Q>hd=Z&}Xsjs4jcIOSj~5J)X^_0r2>kW!c1FyY6~T=EWSyg#hi zpN$D^8H(v%gj$^4Oij5;VlO3$)V2|Cv%>SwWdeE`MN*4BgYD}QHzk9B-a`S@gxBKM z&eSH+izhE4yI7BxaC82gIg?Ni10EfH#V{x|%|W67PejczCt#2|XCqDbAR@SRz+Zyi&cbHd zXix>lh-fC?R44zBD`|o=NfyN`bJ5~n|AilEk!GMU&V-s7=g$TXL~qtjM_RF}axO>I ziR-b6m`_7#A=FSfHTnF-`HR#gpsB=MkEO?>{!m5bn#@T5bX(w z1}QzQgkYXxR{8|8|M4V%BO^41JqLqGjU!S@AhyJ~3+X9ow5re8Kw&d>5!2*Lm*?*_ zfV}EhM2od$Ei?1Snv?qxpD~2se&Qkr*DpUcnyx*KbBMKomhtgF)nES>YMqkd+qqBK z2;gyVZ%dQ@K0%;N$Jv+s{Y@Ao^2fy6^(34bzNh@jH%K)nkvLpP%5(1-W`*SPR@72H zvJs$AaLuz!G47wD^S&qXHlcX#4J1Rak#631nylgkqNxT3-;8Wmvh)V>2a^y;O?u^` zUNC5$3sLM?8INI1+EKa;J!r#TK%%iaPD20kiaBN*i8|3naJFeo?fK_K@*kvz^+eV6 zOvW%JNZFiRjEfIUsvg!|&LQP7q^!PpMRt8q z|2*1{{LqGha2_LDwDgUC2PU7R1^IwDs}KHsQPB9JAW3%=iNanX-(~PyTT*T|CZP8b zNX^c@(Y#nZ_;SQ+P+;Q${;@ zKi_rvk?#SyM2_$_lJ~+}|Id30!rA=u@YH?=|HHF{@8wf@FW>9D9yhfs>?^j*cMk3p z^kt1%QFw3vK7EP*G5rbeFujp?pQv_vnr3psLDMy8k{;gvRZ>3=^nSODT!bq zb?`hCqZohSdt>z{_`(uyA`r+)T4GtPdM!Z@68+j`EKkYB=7GVqmc&>hO+X-;7Q0y` z<=O%Q;sm7RGE6&tLx1B}0%A50xE4nUFKZV0y&P##vw^~ga4tT=FiM?B|MmxJ_T3`d zj;~E9+l06p*OnARvu+$Jj`wJxiJ-MJsesgZZ z^)CtSPZSACMHe*7oPI~0j@ziaa2>h1-_#aehQh$bXMZ3wz{+#i3GH%yzLIX_vfl~8 zaZ+HywUDGxDO_3h8-l52iIC@wlnJRc(_at>T&3Gg#Yf#sEv7rt>}MP8-_E?H*w;Gc zQ1m?e8gX-!D<+>fFLkw_vXY-{u&}u)6|kN(8U~4e1!aJG)>ZT?*GfMgJ(~UjWl;UT z!N1&`Qm-EFfA&2};Ov{2{D~T=?Wd3k-x00bb1dcagN$GM-u(I#qJBAV>QXP%QO=CE z@4vOd^332A>ZT}Pvv9^NTK8{IDDYk6l!Q@xcj}evv^6g&K#GdZ{C8;^uaRk9Bne{l z2n}ubLh<-~3i%gogz(A{Z=>1~{mv~!^lM}t%h{P?*yf^{zmU4lBSNm*VMa<_f5sCz z^Uit04Le7?9mZvOSGG+fT3-?^hht}K$}E{L+W!6m!Qjk`=E3Bqp}u~XXd<5z!x-9; zM#a8GzUGAR8B&GfGS8iE>Z5ym`y3!?&)5ji3UZtwnfgby{fAy8x~GwDtSkMdIMuV* z*P9_TXdJE$PLbrUhc}FmDQnzpP5UyZS|Bs~m6$5Q-_RfV(3*4-Hwe$Pf&SG`7;Jx$ zz`NW7WuvnaxlD_LU6;2I=Y~Ozq7h;%j=z7SBMr zAt@#SEMwl5s;|&xX!a=z0KQY%Lsp&j`o(^~3x zUub4A0*WIbrJrVrC+3zoxgcjZmW0n+@sc(WXx|ZkA3OROy`+W1@3N|bedUyi$|MZ! z@+J8sHUD`T1XH`~7XK+&bR=~}c{v-%dC((SyQ;p|1+B=BHV|Z@u3b^focT_j0o0=A zl~4d!5z2U&zGp5UQ;KwblYnAvFkbac^5EYQfeR8QM(htb2m;QiYTS8;NQ>B0%GmCT7Z_n@W7~gV$dN?*IRw!FTvh`qukKhd%eU z_hou-c@KN%c)NS+czvFeo)w;_J?%Z29-np6TJN84O|rUMbu6EG$=qT-XFhCJfm{8@ zjb+9l;~t}c{MElpejw+|A@UxX4&Md*P`oOJhk(g33zy^~r-Y##!M5{8A?K0W>tec(+- zEFb)zGdGj(m&oXtiZV;G^jNV{%BH^;=*76i6UXg&PU8Qzf3|VVO(Qee7mXUT9P>PX5 zanb4HK-?Ibn1PN4S~H3fOHuw%;+eAq7HL_5p*aE+lbIRbZVzH=At@tMZx8Z)7h#Z& zB8{yuDHm%nWXHy7DGNw~NUICb9LbGfh5K2TXD|iVo`_*oSzNN(a$Fn{>7Bvi zIJbxBzqUln4y46Mvn*_#iVPQj3ngriFM#_n_*T8)%_t-2p?POxRrL->8 zOpDe0VC=5n#VmRrK}6bWVdgI0L$J>t^*y$c_(a-ju>LWO%F^fE=U+}&UIew+)WZQO zyS`Z9EWNT+{A-7e@r~=u?j5klEH04WagA2mcY9&bri}F5K$EU(F7=To%m)k5oFm;6 z@Gdb9gy7A|Zzt`{p!JWm>VS{qJYLAZ$EW=4r-hBQ>cGV+ElMf6w@bRTfta7gnZ^pR zTs-!2pxGD1Jkqp-4d<{bLoXd~d>8d-k+xlImnn^|?-e~u&nk*Y+wR|#$3^4m{tuQx zldV(EwRCaDmOq?N(}uC2cFx~?Hpv|6A;E@m7QosY<>XYliX*}uK0>;RPQ$5XOMX!- zIRUNJ9ezh?TPH>38u*KPIY~I4#gJO^dUOSFAVQLwl2v zZq2{d5{9fZzUU*=SCG-Ro8n_cMmZRiAVeBg;rg2%$}IS1s`cD#VjgLZz}#b0qVNvSuAWDClSU)G zweT4@#Wd4==0eq(bqFZZP64V)nPnQcR%ZS)nt-S^j1lJS9mo^wUbR}gr+dj+MeUr#9vc$Aeg7Q18L&#oAN)ADGWZy48LS=*1uh5n2c`%51Tq6Y|0Vb) z;7k5djQQ{M7iJ56*M0kZ(|m1wCA>GipTg4vgS`#C1w6lbKJ>imnc(T_DPvu;j#{g& zK~@7RzxkE9)|_N^hnog}8V8Iy#$!fPqnP|oZkKc9WAYAZz;^(*iMe8c{)e8euhl2$ zUG-YJN4ucy@uGftB(VYgD*Fl2hF|iX+(ST=*Z>fjpTYh(lkZp|G-@76W?3$j*0)|Nn#yIY{00L!d4o4eZ}_Pf!mHpyd6x!;ntZfD7@9l z+wn;D17ON>3hmHxUSJB*qTDCf7S`T+TrLiOiZ$Fg|1k@#gs&qjQA|`+Sf#y5g$18s z!+^VS7@RPguFGE_+HrcB>{9W^jEzs1Ml+J|d87qdgOcl6yydk51EypCeU>NJ>o z2cM^3^v1wEWDdz8c{ri%p2%*{^PGGx0zuD+fH?nYz3-Swtmh!>SpH4uE9)Awf29i$ z&mmQ{6D--S;9ppC@!3ez+4>f3lVQ-EkXZ-??t*M85EqCe*`6hcSZC?-^W>C49SC72 z$_A-*p7oQ(ey)}BTsB5FJ{>vyi}z%|%n0t=NtQkh`KTF>#a_BE@#k>Hm~(>3BZ&s= z8OPd-l=fX7BubIABAn&W8X0C%iE>ZV<9|GoR)lX!D^|qWp(a-AV`OaMv?Ay5$NAnm zrl)yX1A1*2j~o|*eaBD|(+~FMQ{D@Q7;vpT=b+F&RB}C{Fz#%v&-{UA_A#nfwLVjx zTvaA}8i{-o73oZvI2+c@?2<<7`VrBJAu^W_@X((gTGtaOGI$1;s=#1VkA`X;CYg^D zALXid?eKB%l}_0>gM`L78Q< zX)QiL1oz9|yux{HQuL_eC}O#vn;LBUxwy^^NV@kCEmi^`*y`Ti7w3`w-m?+Fw3KUJ zmcF-WP@@(hKSER;zH8g3?CV~%fQN~a>pez`jl7odE?wc^?-H7;saodzMs?myr6oOt zXwIe=my7nsWmA)oze8X#t~au?@4=u+M4I*x#9XB@^nPosp;t+Z2at_=k_CqFN||M6 z31~k8sV+zullK)UDoB8RHqgH{2c&G+s6f+u32iUZuIyTs!pj}r;@jyRV0@2_2C1EL z$=onTrj^RxOLFff+Dhgt^}Wwp`wtP&E|OcxbPRn^V{2J7PVXd2j(unf@lB!P^u;T_ zgTRz917C*fQF2@hGJv;{q0)2W&{FjqKpPMU@*2{irQNt{o*GL6tS13ncQoTON|~uGi1u1S zQ~aWo-ZS~D-$_8P*+7t#D+i;7{`|Y1aj#MK^(q0Wd2#Af-J^Fv*AR#!?R&GaFZn1j zTWteDa-u{!VSG}nV25vMZC4=>v@>0-(U>&@29bURu~cnKQSiCMsUMRfSCWvf_eKo4 zaai%<+i0JzKr}D_H4`#kzmXWaLJ8<{1ao#I^*fKkAY#iF zo#bsRgtw^YAI~ArGS5?<4xTC=zxAE9-5O^-#Lrt9@GLm)5!;)q~M}W1c%AmW)QH$+}VnSv#MY;~rWQ;SMS-03q6wsA{b zIz5geGKiYu@GUuNL-`Nr5ncg(vPfMOqYEQt#r^p&&_zlSZGE!fK5@ZN#WA;p+iB9P^f{Uy4QDKwBC*$T1DHS4##U5*@5a~$z6y@^E3R0PeqHS zOmA1>W+%*xM5O%*;Xg(_Cz-h9O?{eH$BU|Rs@*ib6Dv1gfzeS=GZexDO@+tTs!lJL z6{)y@km==_k{R{J!a$qnkz)vFgW9;~1Pqjp|BkB-%_?Qqf^QofJbw_4{J;L)|8f5= z@}&gW(29BoE*rRv8hby`vMR}~)q4%ENXMD{do&^lQVJcx8qD^vXw~~2k^-u{+?byyhRTw`8$bILn79Bv1&^F9hDFbFF-&&s zfrPb9Xs&b)pk@n}nJ~M?5<1M~(Zfh3)i!x@-=rnS>E1!~_$9^>vEE}F4D=Kt9kuL; zVbzDp>U1klM2=L#j?X1o6SCqbiCd|!DWWGUG3riXoLpA0^#ts#ipVJotderivj+U& za*H&S*16nFZ*`u%Nbf2XMRAeTq7lArx2Npk@Ut4>v(X|5q#CWoZe*u?LXK1vwt<|T zPP4~w7`S*Ma(o#+79;C7jrr3v3V(pPrYJ~~yFP&~<%-lol}3_E3LqLZvxs)19gTKS z;*cMw;oh#%ryYiY7AjJRZj4xF%Jo%B@9a(TCnFp879JBtn_Bf|5T7I)4a$%h=4coR zL(+%QoA^W`@^R0}O+IBs>dxpIB;b4?lO{beR{D^*7mC`Pr*q&mJRWH~s|QO@sA(;X zrk?qb7KCkuR=v__7eVAm-g&Ej!Sq>j%fAP>@l zjYoY3DaLkBe&!-Awq*l_&!F;jdrWLf@$}0eqcVxAYXQdjeTO|iM>Sy}A6Umc`IzEw zqxgk#Bt5qgV23IPXv}QhCOBse3Bynr$cJ3KoHXXWnD$LRqOBtuI4#nQ$$KWGY@SH8 zH3S0x?n0ZxQ?WAXbEM60AsSSgWIo(nkdS=1CTgAEL?Bq^JhcI@zG~(7e@9gRu@Rgn zo+j%Rh}+qjfc_>RWfKTFrbyD?BZ>82HW27FmKQN*QM_PBibVbENY&@G2iDf$Ou{^Ta;E*#lKOvo@qAhoOR?WZ{Uj7M*B(A z(*nB!GXj0#JAa|j5&yUTef}l>-r7(8N`9~JBi|BznXk960etK45AR;@LhmqdOK%x3 z_nh!7_Vn^(cs$kxYm+s{ddzBO>wj`{|HCS)A!#*6sUvyd)llP>q}J-FL`W=M_Le1&-N+ad^=KoJkE(l1 z`=*6is~as)UmFNAAJv@91tUY5S22qhO_37V0a=PQBAag+8@834-oZE&GS(&)eT(W# z=)q#~5Ycq)!Ued1vR|KDWDfXZ(LJ)c@6cR;?CQ_nhuupYA?+W@vjW&&ujJ>J$M+Hm(*gHZ{#$ zhTAYn5P>{Bw!tLx)<=8)hHMj&&9ml7%Rmx>_U1hEG161dHaZ7Nl69A4Qc#B8oD zBt@=SMXuq>ACJ+4f|D{ll(%Ub{pmbn883*uT^5_Ss93rS_JOd+1Qs>^Cgz`&!#Dck zZao?!gZh+6^5Z2AYd(GaDnO2i+}4PX4{rzZV5C8mT1b zfbt<-vo*z+wX%_7Mp;!-KL4$3+Z&^lM#P99ckg*VpcnsKpcg)g%7zOzIX`!yTM`isG} zJ|U~t?R@{nFFmlnNao^H*yhH$RY#4(B-TTM0ir2Xf`l&%Ce%nDK_YhsntalT!uD&p zmAzv`j*M^|+h{r>&>+#V`e2L*JQyXMw~Xahuti1O%3e63w@1gmsGZuaB0_ioAxIvb z?YlJ5YU#sk*;9<|rbG!#*<+Ul{@CC}KANYpJx1mULKl+4HX%{$~T zT-N=92x3By^TGJ?p}9uy!m+y|0BKpA1`b85CfeP*#E3xKNM4V{r!FhLvLObg|Jz(6 z#MV(vtCUp!gKWQZdE_Mh-*lO?5@meL5>e-UC{j=5M9CKi?G?3gC(xtw*8HZGXJP3T z__lY}PV58-IZMaUq%ZAH{%Rzi=>|t=jyG(@4}t5P=p>*nZ#XE-deUy#B2P zk@gq|f2vd7{abOYR)P$SIUZKV2i!`2`9~b9B@!tLm03kT$~U_`3aJH>c?NkVYg8fk zibAMRo5$F|UdX2R)Gm4|aip8YXq=`nT(U*S)k$r(1=rG45XozyX4CxH&v!zQO~h>A zpLyIVYP@!eoA{b%)<_!LgUuxCYes+XhO;${v4IEX`EDOVX8g*d7`U+pf(<+dT&_*_ zA4|T{7B4`3v68)}Yz@8MMbaTbI*)ot324yo4m6Wiu(jM~tbqFOi9Y>UmolR!6%qfL{)5Jh> z=F6tfY|po09gZ|LM&$ImCT^y0)d(J(hk~jlh(PyxC<{)`t%%&6H(-?Tweg)W?62+q zb_3rDJ71th;NRA_!BlIbHH%nQ7pshAnjaV>S|;$Yxz3zob~DTH>+ppCIzE=)%k#1C z;JN+9>CYjxM!r1R~K77yI97ohIZ^T9c-%3fd zn&joJ(JPgZY`vHaia?SYqNMp>=Ea*x_KF~be7Ho$`1DS>a(5%ueYu_MtOt;&7~YKW zJAQ7K`pGs9_6py!kzp~ycTqjW+*%~ux1ryTeUgOzmk#cJu?(=XsBS1LT_yCyGCbXH ziK*o#Gx+rR<#4$(d-29?Mk*-+;6p2r;#YB`U1B=9oI%N&JJyxkxYC`12ppL#MZ=9| zi_KwIkYPuR!EqI`W+3S+gQXL`#dZNzE;RYBKMa3(Tek@surnUFmHL)UHI8B*8QUtr z!zn{eKuOm}t>{oZJX>&V)pO!6Cg*ypJxc3!980qIjQw^w$0rHZvnfUdDGI4TYtr01 zvp=5*_BV#+A<)H}c%!({JHe zFT{vIs_H(I1Lcx`>5of$UQ7u`(QC`hy6dtZxPcI!6Krx0(zYI(lKyEbx(G`I5gdms z6#*F2gm3mN0(RM9O4scT+^mQp$ultqCvl4R!;HKHf4ICwIH;%EFwG^KODrmcYzqXN zcRrJ`udN(UMrY$0X<4Cj}G2n-e2*OdkR#*sjNsvUN{j_(E^FbDm%mD` zn+-FFyJHNHD^Qe*QS&JLp;xKBBaIwxlJ5%#S5A!_Ga6*PFp$lP z5kb<&^WfNQ!uq1Oo8q$mFZVMe$DrPnu{?mL>c8oT+~dx8y)4=Png`@9=oSP0MSkrdxPN0~J|SN_9^r0)eW5-dj2w{}*~wmT1@DQcPfF7#k^&f-}< zhoebJUbB03Qob#ox3hum}zKc{YhS)X-m#y6E0X#MD2&`_F z%e0ygDsx~mZo=Dw0lW=q6FAM)Bs#1&j(b=DaXXF98{1w?q^S=fgY0vX!z+W?@qrR{ z5GVI+XJF*`qTpR^Ar|bF@##DEUoBt>+L_qaEE1q0kGX>SPYyVrg%;e728WNM^ovmcL? z=vy)n*bMdmeKas3(Ar1}|0|H+|08_F`8???Y2e@%Z5aApof+lD*&_C=ntpR-5V zZK6Bv0@m+QW}UV+Skoh^k!Ds;t9+ij!HqsT;ZKPesk*tl-I7ugdTYP@1RVl)jE z4gM9p5Zn@+6l@Of6S$TTjobJCPVPOq{p6lglTS@NdEn&!leeJyioaR! zyLq)|-Z#gK8W?{}V!-1^O0H~&-MoBUj08M%)gGCXw^d1ADdHL)`Sw1>v?9oq(f z2zay@9E@F-fK98|pwbs73ysG|2?n`|-Zlno3AVzt6(1>xypz?o+4r%^mCuVyz=tE7 zlFnuPaC%C%9})AzF*5gEVMb^ntJD%P4~sE?XrxX*N@{H~cZ88>h#-=E1IrkYv)l$wzL^&pa}v=Gh%tbB zF6Fm~v1tYESx0n`@P`Bugwa`!YSw?P_ZR)~9b|}CUxC3T&t;MucPE`{ zD1ts7uf#ez*b->~y?}}`mZkTN?+*)h-5}d6|j1AP2CrD1tgd%CRkgc+9C-&ZmYNZwE!V;y0&R~} zo@$=)qysq{-w-|nzcN z>ngUrKHj=kVl?nMF$y9q^p2g|snlk?V}rL85LN$x`e)>O1}AJTMpB8GIlWw-)P&A& zhGV%X83a#TXp0iQVJ5ngq&Xot@Vdqrw48+ys`ClG=9`9^UFPBIl7Z z4^=>D`JQHv1E~C}2>|ZOZ%YMlde=*e1VKPI*0H^ePKrkTJ?qTXOQ_xyVX< zTPLrCkX#rn^X#4S7yk$wzF>xz&ns3!DfAV*-g?wFzsgfB+euv1G=b60;kHQ8qmi45 z*S{umCyL(TWHJrSiXxnN_5@C~r^YmWt4(?$4dF}{aKPipQe+nUjuvU2j8}J3jKQfA zOUDyl?0u=|7d`Q`O%&tGR|D!y@0l0-A<={w5x6^2jncC6->7)%U7Ro;CqXeu$;8>@ zT*F*@F#E#q6BEMel5i2MR@IO_;ODc^raM^^}+c?0FrFGd97bPIC%Vp4W< zHk5x2!2ssL^HMBWWfiL*`NG$+5qy&MKYLjm>Xf2l382@dT@&A&4cph7bk>mn|Wjx&{@XbEF1w&&*aP5?? zK$CWDoiqO#(ICU?;aHwtnmu|m-7pby7Zn|?Rw~8?roqLJjlWS5gTba^8o85>6nv!4 zHS~kVAc-Pt()SVg3y@mAPQGKzcQd>?_;v8L;IweTV2@ypV9vm2fgOSQ#+AU}K%+n* zcuN1Qe?@eQf2hBiznI^!k3|RC3&S0w7wqoF<92mBM`(*t(E2oVZ#1X1)0$}AZ>7PP z13xym!#f1Jm?g+r0*F0h3=(` zXm`?@mL<2~4TR5;E$D4puavZp|_`71)@R@NMcWs<_ zSenq{(NaYR7DQZV7QkbY$cRzDEScIlWc#vb)JziJK0>7N`|T)gL~5F4zA0vP7D-Nu zQJ&f*$nL)C`vmnrjawaOJy|LsO7Bz&-d-kD9K{TbTP$eOHFc9OJce&A_(~K; zxQhc?Lz1a!<;z!k9VSs|+{*`UGMcMps7nQuZag&uqq@XI zjD37N#~_S$C}vvR90<-&JO4npNN9JpZow+ogW>NJ!waV5=p86_|6i=!E04WrO9+N#ec6^U0<9-(zhXdm;qK1k) zkxu080f4u?41Wk46BvKf$!Ikmm-awsWQ(UXoI~L;nQaYwEd86uDX?kE z<7JF*zMAXM8+atrQ4F3JfEo0279EEW;yD;cDd5@WR+lwtZ&X2|c(@6-TYBJyT9v0I zKac4@Dko|r!En;4U2q#_<0$4?)OJtK=1$G^-XdI1B8c-e-OR{el8su4NUI1bK*9sH zC1qcpio7%ueCeWvGv3TQKSl&sRZ@h`D~u;#)}PLZ5jj^31p^O&mk))o)tz=kBI)Il z#5nUcUH^7;jxRlQ)~d}&#W1SH8Y1b!}Bp+Y`yF-nC8-#O1zYC?c!N8I3Lm>GL1h+1TW*` zbrdsY;M(CyV{CAvq}OwzNaJ}j7|HV#Q>)v`T*((jcMOf^$v}0=0D6=qRc-O;7>%dK z)H}%=aBM=QiL97pwixg8eDZ?+xO?$x1e`FX5@-58?8dH_yes38fs88?ufzeFOL>bF zDc`UMD%*ILLDi(p=*^#kG(a)uR?NbkkRH#7ze5|*VPYIKvZPZ?`s-aO2NPc`#F7FS zXo-xFugdbnodd>4zWa>XgkCjoN2`&8#EfQ-d`bP0J?8kxBI{D5d!%~A3ZD&cq7Q{9 zg}cM|_mV?bLkIcep(XULP(P~(yz@UVX=iK>UJri2o*|`!ud<%O>A^N+X)x884bKwH zx9gf60`IeAej%_VFp`X6H3Mw|1=t?r3*N>5hqcRUVy5}euwQr){|5RdUFM%|4d&bY zJ?%WE4>}O2dEP#4FSYxaTS4B?;BgqF^Z(%Y|HM7yTg2{zn~B<$88<6h-ycSzmt#cW zoJkp5%9^YQo&Ah_;|nJFi7D$)})X-bQOn0LR)FBXS(W#8S=DOHyBX06}dQM4+)zo0w1T zg+Cl9eq$Wvh&06LaF)FKTC_(z37EL_Qfg99g+DED%LWi)>4f&C~X9k~3GJ&rn?42?0s=u}v#m-O{}t6J$qGxFxsnzy;@->X2 z_)#&Bw+n8wxXx~J$z&tT7oFI?GK@IXPwKw7NFT~iu?kWfGz~WqEry|iuf=G5nY&L&b z+H7?6dBRhY&KWhvJU-)FM)@exez95p1 z1Y>QECe=+t*=-XlhcVt(nO973j~8&u}WmVINf(L z`)2I0<);J#WG3(u60&eIFTrq0+hatIqnjY&_RK(1qB3`05P7@awlzFQ`piTN$~k27 zyx@dfX~{oLRIbhn+;BUxyx^SO{x9Qp{U;>A~ zBgj-!_Q`MgTO^M4p%@X|A}JWRi7_-=@L@bO2N9P`d7c>QHOZJ!sPzsYgM2q1y-mKn zf`Z#CW`@Wa?+RsWL*Z*_XgK!7i2hDBnr+L#9}c}!aLN5w%*wqcU*CC1v{ewv*&N2d z{3T_^VLTMC3y|JlI-_rW77dOes~B3ek;~-A3zTM0$KfNxiqtBlu)Je@V=z9!i_8Xq4|} zNyNSeM^g?`yVUG6v6{nI3tVoAFU~6jb6>@8V)2!NL4CA>7>C}bGw=2ak5+it>{~bisD&8t@`sOo%wTe)#vfvE|w4#8btBp6gb@|{l#kGYMvVIdNE8+bZ57}!u) z6bN}d7X>0wLRYh?&)AG_bl`JigF7D;lys(T+5HKbZ{R*WDTu)QN|O`b;={nRYayUtoe|J;IkkcZz_fDTDZLaQ_U4#1QTrO> z{YAK^@dSuR=_=MJgbSGv!w4!=GEnj6o{aDRbth|mYzgbn>aar02fg`Q=uA40Hlt;r z0)Hy{b@WK|ndqQst7y4sH1b7cd*s>3xJcJX>4-1<6}<6(QFvgudAMxo&(P`6>!F3A z-te~nyun++&x0F-Q-ghjje{ivHv;bmHV5VfMg-~ya{F)jKk@JP&++&6H}V(v+xB^T z6TCZcxP6~p)cV8v#M)~uw}w~^tYQ{7|7Gqp=a|FbnSzR@!Oy{00iWZK@s_*@XY4z+ zgRCV_k^!Uz$!q*#d}wSno-rOWniwVE`+%2y`FX}e`|;HmJv+B))A?K; z&7sGwquKf=W%?D@$eOh3C9lzOxU;@6ML!#J7hH4c2zv%AkXz8Em8x7M_b2bj8>9RA ztkx}6w<$?Lvwz<08fcdyquH-RVNI0Yh3!iHnro;f&z+YHYq|-1Jn0sY%Cm1|;!cRV zz?3T*Y8OwAmfHWThT8LOTCCEV&$W4_ObjX1<7G|ON;?WG@UOm^xDmD4GC5U4?be-9 za7{!*?HOg#TD6k(B%EudCDHO7Nbjy00x9PZ-1mG*Fa**SbJ6b5x~_rtOgfS_Hydi8 zr9?B!UZ`yWQ0~gK(y@j_RwibYG|knbiY93{)gD^>fCk!IwLkcH5p7;swbz<-O*1U&zFbs9EPJlVnLdFPzF!?O7Z8$eL+DhHlE!s&BF)`M$~~gLZzEBu%nk z9-WCBLGz~X^piym+-~;ho^zKq)SmW;Brn>m%`4lZ*0T?5s1=utm1^B86E~tJt*a|) z4{WfDOU8=6(pE+7-4_foqny4v|s5;bqr@GccJOqKwhz1v<@)Q~~R z@_dk*j||p8dm3v};%b^UuheeBhx`?i^#`CARwzt1#O zE+&`V6MREM1Ci*V_12;R}R zHS|nqbf|NvWbh7r)$h&Vi@}k>X2CMSVBjbCuHVAI=s<@+wSeXS%zqHR>^I!s#9zuE zuz$4oL6kqrZf{q!E$cJuptZu9WVN$OSbp=8dE8uT4ma;JE1SvuTfUbs;FTs2M`tBr9+SEGiJ*Y|_! zBNx=9>g^Kz6YoKPO-4M3NBF-p-qS9gVqb|lrI~gCq{p8~{@qp8iw6amEKL=AWZehq z5%KOzVvQa;p4TL;)ma-;wrnaw;k;ua&k9S3g`IeubqQRC-Gkd@upc+9K zPV&IY9(oXdF09Ok2gLHtI{2+7Y!}l_d+nH|3ER_jld9v}YN#dCP163jtO;8&-F#sB z#!TD@n?Lv})lj?GZu`+bk7%g9ZFkuXine!3T8Yb;G<>9nTCv?`fuZRdYPl=0?e@1c z)GoH0BvsP9U1*f>2!~j$y%V*0CEIOQ{p58GwGu6}PKWh1OSYYMDEx+o+9g`1j~C0S z$=cI4vOdjPYdS;JzajVG}`=yWu+A}7lm4Em}RS<#GXKH{xnWQ?PB+6r-@xPQG41w^N}(kZC*KMEj}lz$y%{{G&12Y4VQ~$W5sv3 z)THTY*>ZgOr*;A)!xjp^prKOint9K;x3o1$c8%5FF;T|ulgzdL3StqPz)<~;^RnEST3?h_kp^GdR# z**iAYP^+3Hf4Rk(xDhoiIOUog-~tvG*>T_IqF-pRJrxhjHR=IvVoCFm`iuH%uoczA z+Rdw&i5p?FF2gIyTMn>YR1Ym$@plcir%O#E&0p2#l{62l)5y?JE2@Xs&*=wD@~K(P z$SPSe0csb;M9(T_-XZijAtYbZMH*;HG4Z}T_G+LNmzq_paVZlwikdbWdR!B=OEJf6 z3g1dq`fI#<==r#mX4<^6PhITbE)BJkY-0U-Kaq(WQS*K|maC{;lT96mtW!~YC!64n zb&5@N9-71WmiIWXMCHz}vJMH)n5&|O*$_3Yx$&%q+QsK4W#%oEEh^08>2q`6q!*@X z6H87vZ*%#gDr~jKlZ||sW#Uf2E}Eh^FU~VWS!Ql{x78j;&rRrkGc$1`XwvNEPu0ulmTsbJ{?rbLr_aqgw67x@dRU{BY=ZZZYM2$Do0ht? zMZ+xl+-%s?vl?a>pS#Q^{g6tAj`wPCMD|nwq2fbVX|+$;*`g4QM3C=%1#&Q`I}7xvDrx%XYvI>oej>UF)kK{8`hkvp?0~xG;gs{s(J@U)kD&z zZ*fvUomlQ~H|uu1s>06HbUP*!cLMgHvg=gXZV#Q2Cf|3^)VrsP2%qQHrjsCEeEMl|979^Ydw_RS&Vm@J}*v zBWh?Ttf#477Y~v7Uf9sl=QDaHI*37S%Ik2#AdfS{%CGoYM&i&XZs*-Uosrk!{3!T&VHi>#yQx_Qz1;UuI9R z+t|gR#{a!_%vxzpwjQ(^S~<+i<_YsP^J%k(S=CJ8zw--xJ)gjP@pPV--DdBzHEcTT z%bK!OdWD{(o9P1jAgxaGklW6>?XpuC?BsmFe@*1^Bz{dDLPx5FINOM|Vrp0wNn=yZi&lN} zMGdv5^_F&-qol)BG{T_jGJhucJ-qog+R61{Y`BP2Qs!DHJZE!JOxUy&pb|zbX za(kguQ!>6ca&jm9xBukkU=bzmcBpV^wD2jVHyD0(F$=u+wpH4Oc&Ci-uk(zyHYqbh zdVaM{Tbq)ZA(g)SGZQzWw)>13AV-6M+9fjspNY^wdloxs@sD27rj-&iv~HWl8fYak z!|y4l6ha(W2%6L{^PLJBijG;Tk(3|S$u2Os5S}k5vV1eDO;u3?1L{6rb^Z@3YWP(; z`>gF?rBBkC4pGzUIh0~3{OXdJ;bRXgj<`dKC|K1_3snsa<47oY$L87+Bx^^jk5Dpk zFtl5sR`Zbq>V^ZQhp{6Cx>|C|!WkJsr*>9Ko6e6CW>Rd=ZVj{?spa_XXH{#sl{QK3 z&80Qap0`)UNh^^Wdh&(GY9g3cLQV7MRhmg)RZ>D!weOsUFWd zlpaTbq;1wT0*s6rf!3Q=Q$53Kt(#P@a9uk=Qcjmt8oxje+aMq5;scnzNsoRb9|DKe z3wDETzsM6i^aPYQzw=xIDyskA`u}C6?0kSLOAE-#)$OM`LGYp& z52XyB>5^@MGcZ~bv)ae^s|HYg>x}v6dgXNm&KL5sgheYCc|?Qd8JyP|q&&Ls42-Z? zrR1I(EG0HK$8Bq?ElPeuC!AhIR?XmfdWPKeuJB{(Xh4rx=&(GGt61Py+1OTm;hGwB z!tZ#7^A1s33IK|Wt>r`CnW};I?1V5!wiv5{mKq^Q!A%7;&`N+#>x|fyi5o%ldU=Y< zjt!u8iO?&% zrlD{N!uY^-rgnckO%Ti1MCp(N;YmRlsgR9nsFmz7YkvKC4Yd@6(Nclp8fus9F>SL` zHw&H?iVqDxrOhj)k4gFyN{1Y*Nik8ha7{B4H)>c?b)*u5L2}t8bmZ-xDXGf(Z=A>y zPt8&11$sOotaFV&R9VBXk};!|4rM$;C>?Y79Z{RUi5okpsU|36X6X*($T42^27u7R eNl9D%lLlHcX0+nC9U5rGnEg{+{lBTW`ab}qKDk=} literal 0 HcmV?d00001 diff --git a/outputs/quality_report.json b/outputs/quality_report.json new file mode 100644 index 0000000..d73587a --- /dev/null +++ b/outputs/quality_report.json @@ -0,0 +1,39 @@ +{ + "source_count": 1500, + "accepted_count": 1482, + "rejected_count": 18, + "final_reason_counts": { + "order_date: несуществующая календарная дата": 1, + "order_date: ожидается YYYY-MM-DD или DD.MM.YYYY": 1, + "order_date: пропущено обязательное значение": 1, + "order_id: пропущено обязательное значение": 1, + "quantity: значение должно быть больше нуля": 1, + "quantity: ожидается положительное целое число": 3, + "quantity: пропущено обязательное значение": 1, + "unit_price: больше двух дробных знаков": 1, + "unit_price: ожидается положительная десятичная цена в рублях": 2, + "unit_price: пропущено обязательное значение": 1, + "unit_price: цена должна быть больше нуля": 1, + "Конфликт order_id": 2, + "Нормализованный дубль": 1, + "Точный дубль": 1 + }, + "problem_counts": { + "order_date: несуществующая календарная дата": 1, + "order_date: ожидается YYYY-MM-DD или DD.MM.YYYY": 1, + "order_date: пропущено обязательное значение": 1, + "order_id: пропущено обязательное значение": 1, + "quantity: значение должно быть больше нуля": 1, + "quantity: ожидается положительное целое число": 3, + "quantity: пропущено обязательное значение": 1, + "unit_price: больше двух дробных знаков": 1, + "unit_price: ожидается положительная десятичная цена в рублях": 2, + "unit_price: пропущено обязательное значение": 1, + "unit_price: цена должна быть больше нуля": 1, + "Конфликт order_id": 2, + "Нормализованный дубль": 1, + "Точный дубль": 1 + }, + "accepted_share": 0.988, + "counting_note": "Итоговая причина — первая в порядке проверок. Каждая отброшенная запись учтена по ней один раз. Счётчики проблем пересекаются: запись учитывается один раз по каждой обнаруженной у неё проблеме." +} diff --git a/outputs/rejected_rows.csv b/outputs/rejected_rows.csv new file mode 100644 index 0000000..ea5cb0a --- /dev/null +++ b/outputs/rejected_rows.csv @@ -0,0 +1,19 @@ +record_number,source_header,source_values,reasons +70,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""3"", ""2024-03-27"", ""Электроника"", ""2"", ""3883.24""]","[""Конфликт order_id""]" +195,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""15"", ""2024-03-31"", ""Книги"", ""три"", ""364.67""]","[""quantity: ожидается положительное целое число""]" +232,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""10"", ""03/15/2024"", ""Книги"", ""7"", ""535.88""]","[""order_date: ожидается YYYY-MM-DD или DD.MM.YYYY""]" +248,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""3"", ""2024-03-27"", ""Электроника"", ""3"", ""3883.24""]","[""Конфликт order_id""]" +298,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""13"", ""2024-02-18"", ""Электроника"", ""0"", ""413.14""]","[""quantity: значение должно быть больше нуля""]" +434,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""19"", ""2024-03-26"", ""Книги"", ""3"", ""12.340""]","[""unit_price: больше двух дробных знаков""]" +506,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","["""", ""2024-03-16"", ""Книги"", ""1"", ""2212.09""]","[""order_id: пропущено обязательное значение""]" +526,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""17"", ""2024-02-18"", ""Спорт"", ""6"", ""-12.50""]","[""unit_price: ожидается положительная десятичная цена в рублях""]" +561,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""9"", ""2024-02-30"", ""Товары для дома"", ""4"", ""1456.85""]","[""order_date: несуществующая календарная дата""]" +707,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""16"", ""2024-02-07"", ""Товары для дома"", ""2"", ""0""]","[""unit_price: цена должна быть больше нуля""]" +740,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""5"", """", ""Товары для дома"", ""1"", ""1146.30""]","[""order_date: пропущено обязательное значение""]" +864,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""12"", ""2024-01-06"", ""Спорт"", ""1.5"", ""3825.90""]","[""quantity: ожидается положительное целое число""]" +885,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""2"", ""2024-02-01"", ""Товары для дома"", ""2"", ""1170.27""]","[""Нормализованный дубль""]" +1004,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""7"", ""2024-01-29"", ""Электроника"", """", ""2355.15""]","[""quantity: пропущено обязательное значение""]" +1028,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""8"", ""2024-01-01"", ""Товары для дома"", ""7"", """"]","[""unit_price: пропущено обязательное значение""]" +1243,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""18"", ""2024-01-21"", ""Одежда"", ""4"", ""бесплатно""]","[""unit_price: ожидается положительная десятичная цена в рублях""]" +1420,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""14"", ""2024-03-21"", ""Одежда"", ""-2"", ""3242.83""]","[""quantity: ожидается положительное целое число""]" +1428,"[""order_id"", ""order_date"", ""category"", ""quantity"", ""unit_price""]","[""1"", ""2024-03-22"", ""Книги"", ""5"", ""583.70""]","[""Точный дубль""]" diff --git a/sql/schema.sql b/sql/schema.sql new file mode 100644 index 0000000..ad61852 --- /dev/null +++ b/sql/schema.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS orders ( + order_id INTEGER PRIMARY KEY NOT NULL CHECK (typeof(order_id) = 'integer' AND order_id > 0), + order_date TEXT NOT NULL CHECK ( + length(order_date) = 10 AND order_date >= '0001-01-01' + AND order_date IS date(order_date, '+0 days') + ), + category TEXT NOT NULL CHECK (typeof(category) = 'text' AND length(trim(category)) > 0), + quantity INTEGER NOT NULL CHECK (typeof(quantity) = 'integer' AND quantity > 0), + unit_price_kopecks INTEGER NOT NULL CHECK (typeof(unit_price_kopecks) = 'integer' AND unit_price_kopecks > 0), + revenue_kopecks INTEGER NOT NULL CHECK ( + typeof(revenue_kopecks) = 'integer' AND revenue_kopecks > 0 + AND revenue_kopecks = quantity * unit_price_kopecks + ) +) WITHOUT ROWID; + +CREATE TABLE IF NOT EXISTS daily_category_revenue ( + order_date TEXT NOT NULL CHECK ( + length(order_date) = 10 AND order_date >= '0001-01-01' + AND order_date IS date(order_date, '+0 days') + ), + category TEXT NOT NULL CHECK (typeof(category) = 'text' AND length(trim(category)) > 0), + order_count INTEGER NOT NULL CHECK (typeof(order_count) = 'integer' AND order_count > 0), + revenue_kopecks INTEGER NOT NULL CHECK (typeof(revenue_kopecks) = 'integer' AND revenue_kopecks > 0), + PRIMARY KEY (order_date, category) +) WITHOUT ROWID; diff --git a/src/database.py b/src/database.py new file mode 100644 index 0000000..beabae7 --- /dev/null +++ b/src/database.py @@ -0,0 +1,33 @@ +"""Полная транзакционная загрузка снимка заказов в SQLite.""" + +import sqlite3 +from collections.abc import Iterable +from contextlib import closing +from pathlib import Path + +from .transform import Order + +SCHEMA = Path(__file__).resolve().parents[1] / "sql" / "schema.sql" + + +def reload_database(path: Path, orders: Iterable[Order]) -> None: + schema = SCHEMA.read_text(encoding="utf-8") + path.parent.mkdir(parents=True, exist_ok=True) + with closing(sqlite3.connect(path, isolation_level=None)) as db, db: + # BEGIN внутри скрипта включает в транзакцию и создание таблиц. + db.executescript("BEGIN IMMEDIATE;\n" + schema) + db.execute("DELETE FROM daily_category_revenue") + db.execute("DELETE FROM orders") + db.executemany( + """INSERT INTO orders (order_id, order_date, category, quantity, + unit_price_kopecks, revenue_kopecks) + VALUES (?, ?, ?, ?, ?, ?)""", + ((o.order_id, o.order_date, o.category, o.quantity, o.unit_price_kopecks, + o.revenue_kopecks) for o in orders), + ) + db.execute(""" + INSERT INTO daily_category_revenue (order_date, category, order_count, revenue_kopecks) + SELECT order_date, category, COUNT(*), SUM(revenue_kopecks) + FROM orders + GROUP BY order_date, category + """) diff --git a/src/generate_data.py b/src/generate_data.py index 9952b48..10e4f9c 100644 --- a/src/generate_data.py +++ b/src/generate_data.py @@ -5,8 +5,12 @@ from datetime import date, timedelta from pathlib import Path from random import Random +if __package__: + from .extract import FIELDS +else: # Прямой запуск файла через python src/generate_data.py. + from extract import FIELDS + OUTPUT_PATH = Path(__file__).resolve().parents[1] / "data" / "raw_orders.csv" -FIELDS = ("order_id", "order_date", "category", "quantity", "unit_price") CATEGORIES = ("Книги", "Товары для дома", "Одежда", "Спорт", "Электроника") START_DATE = date(2024, 1, 1) END_DATE = date(2024, 3, 31) diff --git a/src/quality.py b/src/quality.py new file mode 100644 index 0000000..2e76508 --- /dev/null +++ b/src/quality.py @@ -0,0 +1,87 @@ +"""Статистика и экспорт уже обработанного снимка заказов.""" + +import csv +import json +from collections import Counter +from pathlib import Path +from tempfile import TemporaryDirectory + +from .transform import Order, RejectedRecord + +OUTPUT_DIR = Path(__file__).resolve().parents[1] / "outputs" +CLEAN_FIELDS = ("order_id", "order_date", "category", "quantity", "unit_price_kopecks", "revenue_kopecks") +REJECTED_FIELDS = ("record_number", "source_header", "source_values", "reasons") + + +def build_report(accepted: list[Order], rejected: list[RejectedRecord], source_count: int) -> dict: + """Проверить полноту результатов по числу записей, прочитанных из CSV.""" + if len(accepted) + len(rejected) != source_count: + raise ValueError("Число исходных записей не равно сумме принятых и отброшенных") + numbers = {order.record_number for order in accepted} + numbers.update(row.source.record_number for row in rejected) + if numbers != set(range(1, source_count + 1)): + raise ValueError("Исходные номера записей должны покрывать весь снимок без повторов") + + final_reasons = Counter() + problems = Counter() + for row in rejected: + if not row.reasons: + raise ValueError(f"У записи {row.source.record_number} отсутствует причина отбраковки") + final_reasons[row.reasons[0]] += 1 + problems.update(set(row.reasons)) + + return { + "source_count": source_count, + "accepted_count": len(accepted), + "rejected_count": len(rejected), + "final_reason_counts": dict(sorted(final_reasons.items())), + "problem_counts": dict(sorted(problems.items())), + "accepted_share": len(accepted) / source_count if source_count else None, + "counting_note": ( + "Итоговая причина — первая в порядке проверок. Каждая отброшенная запись " + "учтена по ней один раз. Счётчики проблем пересекаются: запись учитывается " + "один раз по каждой обнаруженной у неё проблеме." + ), + } + + +def save_outputs( + accepted: list[Order], rejected: list[RejectedRecord], source_count: int, + output_dir: Path = OUTPUT_DIR, +) -> None: + """В собранном пайплайне вызывать после успешного завершения транзакции БД.""" + report = build_report(accepted, rejected, source_count) + save_reports(accepted, rejected, report, output_dir) + + +def save_reports( + accepted: list[Order], rejected: list[RejectedRecord], report: dict, + output_dir: Path = OUTPUT_DIR, +) -> None: + """Сохранить результаты со статистикой, проверенной до загрузки БД.""" + output_dir.mkdir(parents=True, exist_ok=True) + with TemporaryDirectory(dir=output_dir) as staging: + directory = Path(staging) + clean = directory / "clean_orders.csv" + with clean.open("w", encoding="utf-8-sig", newline="") as output: + writer = csv.writer(output) + writer.writerow(CLEAN_FIELDS) + for order in sorted(accepted, key=lambda item: item.record_number): + writer.writerow([getattr(order, name) for name in CLEAN_FIELDS]) + + rejects = directory / "rejected_rows.csv" + with rejects.open("w", encoding="utf-8-sig", newline="") as output: + writer = csv.writer(output) + writer.writerow(REJECTED_FIELDS) + for row in sorted(rejected, key=lambda item: item.source.record_number): + writer.writerow(( + row.source.record_number, + json.dumps(row.source.header, ensure_ascii=False), + json.dumps(row.source.values, ensure_ascii=False), + json.dumps(row.reasons, ensure_ascii=False), + )) + + quality = directory / "quality_report.json" + quality.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + for path in (clean, rejects, quality): + path.replace(output_dir / path.name) diff --git a/tests/test_extract_transform.py b/tests/test_extract_transform.py index 90d2857..e9be1f8 100644 --- a/tests/test_extract_transform.py +++ b/tests/test_extract_transform.py @@ -1,4 +1,5 @@ import csv +from pathlib import Path import pytest @@ -116,3 +117,62 @@ def test_missing_or_damaged_file(tmp_path): path.write_text(",".join(FIELDS) + '\n1,2024-02-29,"незакрытое поле', encoding="utf-8") with pytest.raises(CSVFileError, match="ошибка структуры CSV"): clean_orders(read_records(path)) + + +def test_invalid_utf8(tmp_path): + path = tmp_path / "orders.csv" + path.write_bytes(",".join(FIELDS).encode() + b"\n1,2024-01-01,\xff,1,1\n") + with pytest.raises(CSVFileError, match="UTF-8") as error: + list(read_records(path)) + assert str(path) in str(error.value) + + +def test_access_denied(tmp_path, monkeypatch): + path = tmp_path / "private.csv" + + def deny_access(self, *args, **kwargs): + raise PermissionError("access denied") + + monkeypatch.setattr(Path, "open", deny_access) + with pytest.raises(CSVFileError, match="ошибка чтения") as error: + list(read_records(path)) + assert str(path) in str(error.value) + assert isinstance(error.value.__cause__, PermissionError) + + +def test_logical_record_numbers_across_multiline_field(tmp_path): + path = tmp_path / "orders.csv" + path.write_bytes((",".join(FIELDS) + '\r\n1,2024-02-29,"дом,\r\nсад",1,10\r\n' + '\r\n2,2024-03-01,книги,2,3\r\n').encode()) + records = list(read_records(path)) + assert [r.record_number for r in records] == [1, 2, 3] + assert records[0].values[2] == "дом,\r\nсад" + assert records[1].structure_error == "Пустая запись CSV" + assert records[2].values[0] == "2" + + +def test_order_and_reasons_across_processing_stages(tmp_path): + conflict = order(order_id="9") + bad = order(quantity="-1", unit_price="0.001") + accepted, rejected = process( + tmp_path, conflict, order(order_id="8"), bad, conflict, + conflict | {"order_date": "29.02.2024"}, order(), bad, + conflict | {"quantity": "2"}, order(order_id="08"), + ) + assert [(o.record_number, o.order_id) for o in accepted] == [(2, 8), (6, 1)] + assert [(r.source.record_number, r.reasons) for r in rejected] == [ + (1, ["Конфликт order_id"]), + (3, ["quantity: ожидается положительное целое число", "unit_price: больше двух дробных знаков"]), + (4, ["Точный дубль"]), + (5, ["Конфликт order_id"]), + (7, ["Точный дубль"]), + (8, ["Конфликт order_id"]), + (9, ["Нормализованный дубль"]), + ] + + +def test_large_price_preserves_last_kopeck(tmp_path): + accepted, rejected = process(tmp_path, order(unit_price="90071992547409,93", quantity="3")) + assert not rejected + assert accepted[0].unit_price_kopecks == 9_007_199_254_740_993 + assert accepted[0].revenue_kopecks == 27_021_597_764_222_979 diff --git a/tests/test_generate_data.py b/tests/test_generate_data.py index 1a11228..1e49edf 100644 --- a/tests/test_generate_data.py +++ b/tests/test_generate_data.py @@ -1,4 +1,6 @@ import csv +from collections import defaultdict +from datetime import date, datetime from src.generate_data import generate_data @@ -18,3 +20,36 @@ def test_repeated_generation_is_byte_identical(tmp_path): first_run = path.read_bytes() generate_data(path) assert path.read_bytes() == first_run + + +def test_planned_examples_are_present_in_generated_csv(tmp_path): + path = tmp_path / "orders.csv" + generate_data(path) + with path.open(encoding="utf-8", newline="") as source: + rows = list(csv.DictReader(source)) + + expected_values = { + "order_id": {""}, + "order_date": {"", "2024-02-30", "03/15/2024"}, + "category": {"", " тОВАРЫ для ДОМА "}, + "quantity": {"", "1.5", "0", "-2", "три"}, + "unit_price": {"", "0", "-12.50", "бесплатно", "12.340", "12,50"}, + } + for field, expected in expected_values.items(): + assert expected <= {row[field] for row in rows}, field + + by_id = defaultdict(list) + for row in rows: + by_id[row["order_id"]].append(row) + first, repeat = by_id["1"] + assert first == repeat + + iso, local = sorted(by_id["2"], key=lambda row: "." in row["order_date"]) + assert date.fromisoformat(iso["order_date"]) == datetime.strptime( + local["order_date"], "%d.%m.%Y" + ).date() + assert iso == local | {"order_date": iso["order_date"]} + + first, conflict = by_id["3"] + assert int(first["quantity"]) != int(conflict["quantity"]) + assert first == conflict | {"quantity": first["quantity"]} diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py new file mode 100644 index 0000000..9982434 --- /dev/null +++ b/tests/test_pipeline.py @@ -0,0 +1,130 @@ +import csv +import json +import os +from pathlib import Path +import shutil +import sqlite3 +import subprocess +import sys +from contextlib import closing + +import pytest + +from src.extract import FIELDS + +ROOT = Path(__file__).resolve().parents[1] +ROWS = [ + (8, "2024-01-01", "Книги", 2, "10,25"), + (3, "01.01.2024", " книги ", 1, "0.50"), + (5, "2024-01-01", "Дом", 3, "1"), + (2, "2024-01-02", "Книги", 1, "5"), + (1, "2024-01-02", "Дом", 0, "2"), +] + + +def write_input(project, rows): + with (project / "data/raw_orders.csv").open("w", encoding="utf-8", newline="") as out: + writer = csv.writer(out) + writer.writerow(FIELDS) + writer.writerows(rows) + + +@pytest.fixture +def project(tmp_path): + folder = tmp_path / "project" + (folder / "data").mkdir(parents=True) + shutil.copy(ROOT / "main.py", folder) + shutil.copytree(ROOT / "sql", folder / "sql") + shutil.copytree(ROOT / "src", folder / "src", ignore=shutil.ignore_patterns("__pycache__")) + write_input(folder, ROWS) + return folder + + +def run(project, *, success=True): + result = subprocess.run( + [sys.executable, str(project / "main.py")], cwd=project.parent, + env={**os.environ, "PYTHONIOENCODING": "utf-8"}, capture_output=True, encoding="utf-8", + ) + if success: + assert result.returncode == 0, result.stderr + else: + assert result.returncode != 0 + assert not result.stdout + return result + + +def snapshot(project): + with closing(sqlite3.connect(project / "outputs/orders.db")) as db: + orders = db.execute("SELECT * FROM orders ORDER BY order_id").fetchall() + daily = db.execute("SELECT * FROM daily_category_revenue ORDER BY order_date, category").fetchall() + return orders, daily + + +def test_full_run_and_repeat(project): + run(project) + orders, daily = snapshot(project) + assert len(orders) == 4 + assert daily == [ + ("2024-01-01", "Дом", 1, 300), ("2024-01-01", "Книги", 2, 2100), + ("2024-01-02", "Книги", 1, 500), + ] + for day, category, count, revenue in daily: + amounts = [row[5] for row in orders if (row[1], row[2]) == (day, category)] + assert (len(amounts), sum(amounts)) == (count, revenue) + + outputs = project / "outputs" + with (outputs / "clean_orders.csv").open(encoding="utf-8-sig", newline="") as source: + clean = list(csv.DictReader(source)) + assert sorted((int(r["order_id"]), r["order_date"], r["category"], int(r["quantity"]), + int(r["unit_price_kopecks"]), int(r["revenue_kopecks"])) for r in clean) == orders + with (outputs / "rejected_rows.csv").open(encoding="utf-8-sig", newline="") as source: + assert [r["record_number"] for r in csv.DictReader(source)] == ["5"] + report = json.loads((outputs / "quality_report.json").read_text(encoding="utf-8")) + assert (report["source_count"], report["accepted_count"], report["rejected_count"]) == (5, 4, 1) + run(project) + assert snapshot(project) == (orders, daily) + + +def test_aggregate_overflow_rolls_back_both_tables(project): + run(project) + before = snapshot(project) + write_input(project, [ + (99, "2025-01-01", "Дом", 1, "92233720368547758.07"), + (100, "2025-01-01", "Дом", 1, "0.01"), + ]) + assert "integer overflow" in run(project, success=False).stderr + assert snapshot(project) == before + report = json.loads((project / "outputs/quality_report.json").read_text(encoding="utf-8")) + assert report["source_count"] == len(ROWS) + + +def test_damaged_input_preserves_database(project): + run(project) + before = snapshot(project) + with (project / "data/raw_orders.csv").open("a", encoding="utf-8") as out: + out.write('123,2024-01-20,"незакрытое поле') + assert "ошибка структуры CSV" in run(project, success=False).stderr + assert snapshot(project) == before + + +def test_no_accepted_orders_clears_both_tables(project): + run(project) + write_input(project, [ROWS[-1]]) + run(project) + assert snapshot(project) == ([], []) + report = json.loads((project / "outputs/quality_report.json").read_text(encoding="utf-8")) + assert report["rejected_count"] == 1 + + +def test_export_error_after_commit(project): + run(project) + write_input(project, [ROWS[2]]) + blocked = project / "outputs/clean_orders.csv" + blocked.unlink() + blocked.mkdir() + result = run(project, success=False) + assert "База уже обновлена" in result.stderr + assert "clean_orders.csv" in result.stderr + assert snapshot(project) == ( + [(5, "2024-01-01", "Дом", 3, 100, 300)], [("2024-01-01", "Дом", 1, 300)] + ) diff --git a/tests/test_quality.py b/tests/test_quality.py new file mode 100644 index 0000000..d0f9f74 --- /dev/null +++ b/tests/test_quality.py @@ -0,0 +1,80 @@ +import codecs +import csv +import json + +import pytest + +from src.extract import FIELDS, read_records +from src.quality import build_report, save_outputs +from src.transform import clean_orders + + +def read_csv(path): + assert path.read_bytes().startswith(codecs.BOM_UTF8) + with path.open(encoding="utf-8-sig", newline="") as source: + return list(csv.reader(source)) + + +def test_export_and_replace_snapshot(tmp_path): + path = tmp_path / "raw.csv" + header = ("category", "order_id", "quantity", "order_date", "unit_price") + bad = ['дом, "сад"\nспорт', "2", "", "?", "0"] + good = [" КНИГИ ", "7", "3", "29.02.2024", "0,07"] + extra = good + ["лишнее"] + rows = [good, bad, bad, extra, [], ["", "4", "1", "2024-01-01", "10"]] + with path.open("w", encoding="utf-8", newline="") as output: + writer = csv.writer(output) + writer.writerow(header) + writer.writerows(rows) + records = list(read_records(path)) + accepted, rejected = clean_orders(records) + directory = tmp_path / "outputs" + save_outputs(accepted[::-1], rejected[::-1], len(records), directory) + clean = directory / "clean_orders.csv" + rejects = directory / "rejected_rows.csv" + report_file = directory / "quality_report.json" + clean_header = ["order_id", "order_date", "category", "quantity", "unit_price_kopecks", "revenue_kopecks"] + reject_header = ["record_number", "source_header", "source_values", "reasons"] + assert read_csv(clean) == [ + clean_header, ["7", "2024-02-29", "Книги", "3", "7", "21"], + ["4", "2024-01-01", "Не указана", "1", "1000", "1000"], + ] + columns, *exported = read_csv(rejects) + assert columns == reject_header + assert [int(row[0]) for row in exported] == [2, 3, 4, 5] + for row, rejection in zip(exported, rejected, strict=True): + assert json.loads(row[1]) == list(header) + assert json.loads(row[2]) == rows[int(row[0]) - 1] + assert json.loads(row[3]) == rejection.reasons + + report = json.loads(report_file.read_text(encoding="utf-8")) + assert (report["source_count"], report["accepted_count"], report["rejected_count"]) == (6, 2, 4) + assert report["accepted_share"] == 2 / 6 + assert report["final_reason_counts"] == { + "order_date: ожидается YYYY-MM-DD или DD.MM.YYYY": 1, "Точный дубль": 1, + "Число полей: ожидалось 5, получено 6": 1, "Пустая запись CSV": 1, + } + assert report["problem_counts"] == report["final_reason_counts"] | { + "quantity: пропущено обязательное значение": 1, "unit_price: цена должна быть больше нуля": 1, + } + before = {file: file.read_bytes() for file in directory.iterdir()} + save_outputs(accepted, rejected, len(records), directory) + assert before == {file: file.read_bytes() for file in directory.iterdir()} + + save_outputs([], [], 0, directory) + assert read_csv(clean) == [clean_header] + assert read_csv(rejects) == [reject_header] + report = json.loads(report_file.read_text(encoding="utf-8")) + assert report["accepted_share"] is None + assert report["source_count"] == report["accepted_count"] == report["rejected_count"] == 0 + assert report["final_reason_counts"] == report["problem_counts"] == {} + + +def test_invalid_accounting(tmp_path): + source = tmp_path / "raw.csv" + source.write_text(",".join(FIELDS) + "\n1,2024-01-01,x,1,1\n", encoding="utf-8") + accepted, rejected = clean_orders(read_records(source)) + with pytest.raises(ValueError, match="сумме"): + build_report(accepted, rejected, 2) + with pytest.raises(ValueError, match="без повторов"): + build_report(accepted * 2, rejected, 2)