{"behavior":"degenerate_repetition","label_filter":null,"limit":10,"next_offset":21861,"offset":21851,"previous_offset":null,"rows":[{"assistant_initiates":false,"asst_text":"Trong l\u0129nh v\u1ef1c thi\u1ebft k\u1ebf trang web, CSS (Cascading Style Sheets) l\u00e0 m\u1ed9t c\u00f4ng c\u1ee5 quan tr\u1ecdng cho ph\u00e9p c\u00e1c nh\u00e0 ph\u00e1t tri\u1ec3n \u0111\u1ecbnh d\u1ea1ng v\u00e0 b\u1ed1 tr\u00ed c\u00e1c th\u00e0nh ph\u1ea7n HTML tr\u00ean trang web theo c\u00e1ch th\u1ee9c linh ho\u1ea1t v\u00e0 phong ph\u00fa. M\u1ed9t trong nh\u1eefng \u1ee9ng d\u1ee5ng ph\u1ed5 bi\u1ebfn c\u1ee7a CSS l\u00e0 thay \u0111\u1ed5i ki\u1ec3u d\u00e1ng c\u1ee7a si\u00eau li\u00ean k\u1ebft \u0111\u1ec3 t\u1ea1o ra tr\u1ea3i nghi\u1ec7m ng\u01b0\u1eddi d\u00f9ng t\u1ed1t h\u01a1n.\n\nSi\u00eau li\u00ean k\u1ebft, th\u01b0\u1eddng \u0111\u01b0\u1ee3c bi\u1ec3u di\u1ec5n b\u1eb1ng th\u1ebb `<a>`, l\u00e0 m\u1ed9t ph\u1ea7n t\u1eed HTML cho ph\u00e9p \u0111i\u1ec1u h\u01b0\u1edbng t\u1eeb trang n\u00e0y sang trang kh\u00e1c. CSS cung c\u1ea5p c\u00e1c l\u1edbp gi\u1ea3 (pseudo-classes) \u0111\u1eb7c bi\u1ec7t cho ph\u00e9p thay \u0111\u1ed5i ki\u1ec3u d\u00e1ng c\u1ee7a si\u00eau li\u00ean k\u1ebft d\u1ef1a tr\u00ean tr\u1ea1ng th\u00e1i t\u01b0\u01a1ng t\u00e1c c\u1ee7a ng\u01b0\u1eddi d\u00f9ng v\u1edbi li\u00ean k\u1ebft \u0111\u00f3. C\u00e1c tr\u1ea1ng th\u00e1i ph\u1ed5 bi\u1ebfn bao g\u1ed3m \"li\u00ean k\u1ebft ch\u01b0a truy c\u1eadp\", \"li\u00ean k\u1ebft \u0111\u00e3 truy c\u1eadp\", \"li\u00ean k\u1ebft \u0111\u01b0\u1ee3c nh\u1ea5n gi\u1eef\", v\u00e0 \"li\u00ean k\u1ebft khi di chu\u1ed9t qua\".\n\n\u0110\u1ec3 thay \u0111\u1ed5i ki\u1ec3u c\u1ee7a m\u1ed9t si\u00eau li\u00ean k\u1ebft trong tr\u1ea1ng th\u00e1i b\u00ecnh th\u01b0\u1eddng, t\u1ee9c l\u00e0 tr\u01b0\u1edbc khi ng\u01b0\u1eddi d\u00f9ng t\u01b0\u01a1ng t\u00e1c v\u1edbi n\u00f3, l\u1edbp gi\u1ea3 `.a:link` \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng. \u0110\u00e2y l\u00e0 l\u1edbp gi\u1ea3 m\u00e0 b\u1ea1n s\u1ebd s\u1eed d\u1ee5ng \u0111\u1ec3 \u0111\u1ecbnh d\u1ea1ng si\u00eau li\u00ean k\u1ebft khi ch\u00fang ch\u01b0a \u0111\u01b0\u1ee3c nh\u1ea5p v\u00e0o. V\u00ed d\u1ee5, b\u1ea1n c\u00f3 th\u1ec3 s\u1eed d\u1ee5ng `.a:link` \u0111\u1ec3 \u0111\u1eb7t m\u00e0u ch\u1eef l\u00e0 m\u00e0u xanh, font ch\u1eef l\u00e0 ch\u1eef nghi\u00eang, ho\u1eb7c th\u00eam g\u1ea1ch ch\u00e2n cho si\u00eau li\u00ean k\u1ebft \u0111\u00f3.\n\nNgo\u00e0i tr\u1ea1ng th\u00e1i b\u00ecnh th\u01b0\u1eddng, l\u1edbp gi\u1ea3 kh\u00e1c nh\u01b0 `.a:hover` cho ph\u00e9p b\u1ea1n thay \u0111\u1ed5i ki\u1ec3u d\u00e1ng c\u1ee7a si\u00eau li\u00ean k\u1ebft khi ng\u01b0\u1eddi d\u00f9ng di chu\u1ed9t qua n\u00f3, th\u01b0\u1eddng \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng \u0111\u1ec3 cung c\u1ea5p feedback tr\u1ef1c quan k\u1ecbp th\u1eddi, gi\u00fap ng\u01b0\u1eddi d\u00f9ng bi\u1ebft r\u1eb1ng si\u00eau li\u00ean k\u1ebft n\u00e0y c\u00f3 th\u1ec3 nh\u1ea5p v\u00e0o. T\u01b0\u01a1ng t\u1ef1, `.a:active` thay \u0111\u1ed5i ki\u1ec3u si\u00eau li\u00ean k\u1ebft khi ng\u01b0\u1eddi d\u00f9ng nh\u1ea5n gi\u1eef chu\u1ed9t xu\u1ed1ng; l\u1edbp n\u00e0y c\u00f3 t\u00e1c d\u1ee5ng trong m\u1ed9t kho\u1ea3ng th\u1eddi gian r\u1ea5t ng\u1eafn, th\u01b0\u1eddng l\u00e0 ngay khi ng\u01b0\u1eddi d\u00f9ng b\u1eaft \u0111\u1ea7u nh\u1ea5n v\u00e0o li\u00ean k\u1ebft. Cu\u1ed1i c\u00f9ng, `.a:visited` \u0111\u1ecbnh d\u1ea1ng c\u00e1c li\u00ean k\u1ebft m\u00e0 ng\u01b0\u1eddi d\u00f9ng \u0111\u00e3 truy c\u1eadp, cho ph\u00e9p h\u1ecd nh\u1eadn bi\u1ebft c\u00e1c trang \u0111\u00e3 th\u0103m.\n\nHi\u1ec3u r\u00f5 v\u00e0 s\u1eed d\u1ee5ng th\u00e0nh th\u1ea1o c\u00e1c l\u1edbp gi\u1ea3 n\u00e0y kh\u00f4ng ch\u1ec9 c\u1ea3i thi\u1ec7n t\u00ednh th\u1ea9m m\u1ef9 c\u1ee7a trang web m\u00e0 c\u00f2n c\u1ea3i thi\u1ec7n s\u1ef1 th\u00e2n thi\u1ec7n v\u1edbi ng\u01b0\u1eddi d\u00f9ng, gi\u00fap \u0111i\u1ec1u h\u01b0\u1edbng trang tr\u1edf n\u00ean d\u1ec5 d\u00e0ng v\u00e0 tr\u1ef1c quan h\u01a1n.","behavior":"degenerate_repetition","conversation_hash":"981ec58056356dd1ac994f5c4484c5ee","conversation_redacted":false,"conversation_toxic":false,"country":"United States","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"English","model":"gpt-4o-2024-08-06","n_chars":2499,"n_turns_in_conversation":1,"n_words":502,"source_row_offset":21851,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:25 GMT","turn_id":"e59b88134724db0f29398644","turn_index":0,"user_text":"Write a educational passage in Vietnamese that could appear in a textbook, giving some paragraphs or pharse that related to this question and answer set:\nC\u00e2u h\u1ecfi: Khi mu\u1ed1n thay \u0111\u1ed5i ki\u1ec3u c\u1ee7a si\u00eau li\u00ean k\u1ebft trong tr\u1ea1ng th\u00e1i b\u00ecnh th\u01b0\u1eddng, b\u1ea1n s\u1eed d\u1ee5ng l\u1edbp gi\u1ea3 n\u00e0o trong CSS?\nA. a:hover.\nB. a:active.\nC. a:visited.\nD. a:link.\n\u0110\u00e1p \u00e1n \u0111\u00fang: a:link\nNotes that:\n1. Remember that the multichoice question above must not be included in the paragraphs or phrase\n2. You can not take an example same as the question\n3. Explain detail like in the actual textbook\n4. All instructions must be given in general form"},{"assistant_initiates":false,"asst_text":"PhET Interactive Simulations l\u00e0 m\u1ed9t d\u1ef1 \u00e1n gi\u00e1o d\u1ee5c n\u1ed5i ti\u1ebfng \u0111\u01b0\u1ee3c ph\u00e1t tri\u1ec3n b\u1edfi \u0110\u1ea1i h\u1ecdc Colorado Boulder, nh\u1eb1m cung c\u1ea5p c\u00e1c m\u00f4 ph\u1ecfng t\u01b0\u01a1ng t\u00e1c mi\u1ec5n ph\u00ed cho h\u1ecdc sinh v\u00e0 gi\u00e1o vi\u00ean tr\u00ean to\u00e0n th\u1ebf gi\u1edbi. M\u1ee5c ti\u00eau c\u1ee7a PhET l\u00e0 c\u1ea3i thi\u1ec7n kh\u1ea3 n\u0103ng h\u1ecdc t\u1eadp v\u00e0 gi\u1ea3ng d\u1ea1y th\u00f4ng qua vi\u1ec7c s\u1eed d\u1ee5ng c\u00f4ng ngh\u1ec7 ti\u00ean ti\u1ebfn \u0111\u1ec3 t\u1ea1o ra c\u00e1c c\u00f4ng c\u1ee5 h\u1ecdc t\u1eadp sinh \u0111\u1ed9ng v\u00e0 h\u1ea5p d\u1eabn.\n\nC\u00e1c m\u00f4 ph\u1ecfng PhET t\u1eadp trung ch\u1ee7 y\u1ebfu v\u00e0o c\u00e1c l\u0129nh v\u1ef1c khoa h\u1ecdc v\u00e0 to\u00e1n h\u1ecdc, bao g\u1ed3m v\u1eadt l\u00fd, h\u00f3a h\u1ecdc, sinh h\u1ecdc v\u00e0 to\u00e1n h\u1ecdc ph\u1ed5 th\u00f4ng. Nh\u1eefng m\u00f4 ph\u1ecfng n\u00e0y cho ph\u00e9p ng\u01b0\u1eddi h\u1ecdc kh\u00e1m ph\u00e1 v\u00e0 t\u00ecm hi\u1ec3u c\u00e1c kh\u00e1i ni\u1ec7m ph\u1ee9c t\u1ea1p m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng th\u00f4ng qua c\u00e1c th\u00ed nghi\u1ec7m m\u00f4 ph\u1ecfng, b\u00e0i t\u1eadp t\u01b0\u01a1ng t\u00e1c v\u00e0 h\u00ecnh \u1ea3nh minh h\u1ecda s\u1ed1ng \u0111\u1ed9ng.\n\nM\u1ed9t trong nh\u1eefng \u0111i\u1ec3m m\u1ea1nh c\u1ee7a c\u00e1c m\u00f4 ph\u1ecfng PhET l\u00e0 ch\u00fang cho ph\u00e9p h\u1ecdc sinh t\u1ef1 do thay \u0111\u1ed5i c\u00e1c th\u00f4ng s\u1ed1 trong c\u00e1c th\u00ed nghi\u1ec7m m\u00f4 ph\u1ecfng, t\u1eeb \u0111\u00f3 quan s\u00e1t v\u00e0 ph\u00e2n t\u00edch nh\u1eefng t\u00e1c \u0111\u1ed9ng c\u1ee7a c\u00e1c y\u1ebfu t\u1ed1 kh\u00e1c nhau. \u0110i\u1ec1u n\u00e0y kh\u00f4ng ch\u1ec9 gi\u00fap h\u1ecdc sinh hi\u1ec3u s\u00e2u h\u01a1n v\u1ec1 l\u00fd thuy\u1ebft m\u00e0 c\u00f2n k\u00edch th\u00edch s\u1ef1 t\u00f2 m\u00f2 v\u00e0 kh\u1ea3 n\u0103ng t\u01b0 duy \u0111\u1ed9c l\u1eadp.\n\nNgo\u00e0i ra, PhET c\u0169ng \u0111\u01b0\u1ee3c thi\u1ebft k\u1ebf \u0111\u1ec3 h\u1ed7 tr\u1ee3 vi\u1ec7c h\u1ecdc t\u1eadp ch\u1ee7 \u0111\u1ed9ng v\u00e0 h\u1ee3p t\u00e1c. Gi\u00e1o vi\u00ean c\u00f3 th\u1ec3 d\u1ec5 d\u00e0ng s\u1eed d\u1ee5ng c\u00e1c c\u00f4ng c\u1ee5 n\u00e0y \u0111\u1ec3 t\u1ea1o ra c\u00e1c ho\u1ea1t \u0111\u1ed9ng nh\u00f3m, th\u1ea3o lu\u1eadn l\u1edbp ho\u1eb7c b\u00e0i t\u1eadp th\u1ef1c h\u00e0nh trong nhi\u1ec1u b\u1ed1i c\u1ea3nh gi\u00e1o d\u1ee5c kh\u00e1c nhau, t\u1eeb l\u1edbp h\u1ecdc truy\u1ec1n th\u1ed1ng \u0111\u1ebfn h\u1ecdc tr\u1ef1c tuy\u1ebfn.\n\nNh\u1edd v\u00e0o s\u1ef1 ti\u1ec7n l\u1ee3i v\u00e0 ch\u1ea5t l\u01b0\u1ee3ng c\u1ee7a c\u00e1c m\u00f4 ph\u1ecfng n\u00e0y, PhET Interactive Simulations \u0111\u00e3 tr\u1edf th\u00e0nh m\u1ed9t ngu\u1ed3n t\u00e0i nguy\u00ean qu\u00fd gi\u00e1 cho h\u00e0ng tri\u1ec7u ng\u01b0\u1eddi h\u1ecdc tr\u00ean kh\u1eafp th\u1ebf gi\u1edbi, g\u00f3p ph\u1ea7n n\u00e2ng cao ch\u1ea5t l\u01b0\u1ee3ng gi\u00e1o d\u1ee5c v\u00e0 th\u00fac \u0111\u1ea9y ni\u1ec1m \u0111am m\u00ea khoa h\u1ecdc v\u00e0 to\u00e1n h\u1ecdc trong c\u00e1c th\u1ebf h\u1ec7 tr\u1ebb.","behavior":"degenerate_repetition","conversation_hash":"e8127cbd6ddffad5753ac76f98ac8f9c","conversation_redacted":false,"conversation_toxic":false,"country":"United States","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"English","model":"gpt-4o-2024-08-06","n_chars":2146,"n_turns_in_conversation":1,"n_words":448,"source_row_offset":21852,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:31 GMT","turn_id":"ee71409ed6065c158ffab2ab","turn_index":0,"user_text":"Write a educational passage in Vietnamese that could appear in a textbook, giving some paragraphs or pharse that related to this question and answer set:\nC\u00e2u h\u1ecfi: PhET Interactive Simulations cung c\u1ea5p c\u00e1c m\u00f4 ph\u1ecfng mi\u1ec5n ph\u00ed trong l\u0129nh v\u1ef1c:\nA. Kinh doanh.\nB. Khoa h\u1ecdc v\u00e0 To\u00e1n h\u1ecdc.\nC. Thi\u1ebft k\u1ebf \u0111\u1ed3 h\u1ecda.\nD. Y t\u1ebf.\n\u0110\u00e1p \u00e1n \u0111\u00fang: Khoa h\u1ecdc v\u00e0 To\u00e1n h\u1ecdc\nNotes that:\n1. Remember that the multichoice question above must not be included in the paragraphs or phrase\n2. You can not take an example same as the question\n3. Explain detail like in the actual textbook\n4. All instructions must be given in general form"},{"assistant_initiates":false,"asst_text":"```json\n{\n  \"task\": \"edit-content\",\n  \"folderName\": \"\",\n  \"fileName\": \"server.js\",\n  \"baseName\": \"testModels/hotelmgt\",\n  \"prompt\": {\n    \"task_id\": \"_draftID_009\",\n    \"task_name\": \"Create Node.js Server with Express\",\n    \"description\": \"Generate a Node.js server.js file with specified features and dependencies\",\n    \"input\": {\n      \"db\": \"connect from ../config/db.js\",\n      \"authentication\": \"helmet, express-rate-limiter\"\n    },\n    \"output\": \"Return the full server.js code with error handling and routers setup\",\n    \"dependencies\": [\n      \"Initialize the database connection using ../config/db.js.\",\n      \"Set CORS configuration for methods POST, GET, and allow origin '*'.\",\n      \"Set the server port number to 4000.\",\n      \"Use express and express body-parser middleware.\",\n      \"Implement helmet and express-rate-limiter for security.\",\n      \"Import the router from ./src/router/authRoutes.js with endpoint of /auth.\",\n      \"Import the router from ./src/router/todoRoutes.js with endpoint of /todo.\",\n      \"Create error handling middleware for routers.\",\n      \"Ensure all specified security measures are implemented.\"\n    ],\n    \"status\": \"pending\",\n    \"isImport\": false,\n    \"readSupportFile\": {\n      \"read\": false,\n      \"folder\": \"\",\n      \"file\": \"\",\n      \"fileData\": \"\"\n    }\n  }\n}\n```","behavior":"degenerate_repetition","conversation_hash":"903f0cf70e62a68339f2076edfb5d34f","conversation_redacted":false,"conversation_toxic":false,"country":"Russia","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"English","model":"gpt-4o-2024-08-06","n_chars":6154,"n_turns_in_conversation":1,"n_words":746,"source_row_offset":21853,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:32 GMT","turn_id":"fc5e29cfb676e7d26404251e","turn_index":0,"user_text":"User: \n\t\tExample of response object model :\n\n\t\t\t\t\t\t{\n\t\t\t\t\"task\": \"edit-content\",\n\t\t\t\t\"folderName\": \"src/controllers\",\n\t\t\t\t\"fileName\": \"bookingController.js\",\n\t\t\t\t\"baseName\": \"testModels/hotelmgt\",\n\t\t\t\t\"prompt\": {\n\t\t\t\t\"task_id\": \"_draftID_008\",\n\t\t\t\t\"task_name\": \"Create Handle Recurring Bookings Api\",\n\t\t\t\t\"description\": \"Generate a Node.js Handle Recurring Bookings Api with given dependenceis\",\n\t\t\t\t\"input\": {\n\t\t\t\t\t\"db\": \"mongoose\",\n\t\t\t\t\t\"authentication\": \"\"\n\t\t\t\t},\n\t\t\t\t\"output\": \"Return only the function code as specified in dependencies\",\n\t\t\t\t\"dependencies\": [\n\t\t\t\t\t\"Create a Api to manage recurring bookings. Export: exports.createRecurringBooking = async () => {...}\",\n\t\t\t\t\t\"Accept data from user: startDate, endDate, frequency (e.g., weekly, monthly), roomId.\",\n\t\t\t\t\t\"Validate required fields: Ensure startDate, endDate, frequency, and roomId are provided.\",\n\t\t\t\t\t\"Use a scheduling library (e.g., node-cron) to generate recurring booking dates based on the frequency.\",\n\t\t\t\t\t\"Check availability for each recurring date using the checkAvailability function.\",\n\t\t\t\t\t\"Create bookings for each recurring date and link them to the same user or service.\",\n\t\t\t\t\t\"Respond to user with a success message containing the booking details for each occurrence.\",\n\t\t\t\t\t\"Handle errors like conflicting bookings, invalid parameters, or database issues.\"\n\t\t\t\t],\n\t\t\t\t\"status\": \"pending\",\n\t\t\t\t\"isImport\": false,\n\t\t\t\t\"readSupportFile\": {\n\t\t\t\t\t\"read\": false,\n\t\t\t\t\t\"folder\": \"\",\n\t\t\t\t\t\"file\": \"\",\n\t\t\t\t\t\"fileData\": \"\"\n\t\t\t\t},\n\t\t\t\t}\n\t\t\t\t}\n\t\t\nUser: These are training datas for dependencies generation. :- \n\t\t\t\n\t\t\t\"Database initialization\",\n        \"Set up cors congif these methods POST, GET and origin is '*' \",\n        \"Create server port number as 4000\",\n        \"use express and express bodyparser\",\n        \"User helemt and rate limitter for security\",\n        \"import the router from this folder ./src/router/authRoutes.js with endpoint of /auth \",\n        \"import Database module form ./config/db.js file as DB, \",\n        \"Create error handelling middleware for routers\",\n        \"Measure all security features are implemented\",\n\t\t \"Create a Api to manage recurring bookings. Export: exports.createRecurringBooking = async () => {...}\",\n        \"Validate required fields: Ensure startDate, endDate, frequency, and roomId are provided.\",\n        \"Use a scheduling library (e.g., node-cron) to generate recurring booking dates based on the frequency.\",\n        \"Check availability for each recurring date using the checkAvailability function.\",\n        \"Create bookings for each recurring date and link them to the same user or service.\",\n        \"Respond to user with a success message containing the booking details for each occurrence.\",\n        \"Handle errors like conflicting bookings, invalid parameters, or database issues.\",\n\t\t \"Create a Api to manage recurring bookings. Export: exports.createRecurringBooking = async () => {...}\",\n        \"Validate required fields: Ensure startDate, endDate, frequency, and roomId are provided.\",\n        \"Use a scheduling library (e.g., node-cron) to generate recurring booking dates based on the frequency.\",\n        \"Check availability for each recurring date using the checkAvailability function.\",\n        \"Create bookings for each recurring date and link them to the same user or service.\",\n        \"Respond to user with a success message containing the booking details for each occurrence.\",\n        \"Handle errors like conflicting bookings, invalid parameters, or database issues.\",\n\t\t \"Create a Api to add a user to the waitlist for a fully booked date. Export: exports.addToWaitlist = async () => {...}\",\n        \"Accept data from user body: userId, checkInDate, checkOutDate, hotelIds.\",\n        \"Validate required fields: Ensure userId, checkInDate, checkOutDate, and hotelIds are provided.\",\n        \"If the requested date is fully booked, add the user to the waitlist for that date.\",\n        \"Store waitlist data with date, hotelIds, userId, and priority level.\",\n        \"When a booking is canceled, notify users on the waitlist and offer the available slot.\",\n        \"Respond to user with a success message confirming the user has been added to the waitlist.\",\n      ],\n\t\t\t\nUser: \n\t\t    You have to create dependencies to instructions for gpt model to create application components by given dicriptions. ,Create instructions for a Node.js server. Specs : express, express-rate-limitter, helmet, connect db from this ../config/db.js file. handel all router error.,port will be 4000, make sure all security,import the router  ./src/router/authRoutes.js with endpoint of /auth ,import the router  ./src/router/todoRoutes.js with endpoint of /todo \n\n\t\tfileName : server.js\n\t\tfolderName : \n    \tbaseName: testModels/hotelmgt\n\n\n\t\tPlease generate a json object in the given model.\n\t\t\t\nAssistant:"},{"assistant_initiates":false,"asst_text":"\u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u0430\u0442\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442 \u0432 \u0432\u0430\u0448\u0438\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044f\u0445, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0430\u0433\u043e\u0432. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432 `MainActivity` \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \n\n### \u0428\u0430\u0433 1: \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 `ConvertCurrencyTask` \u0434\u043b\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u0434\u0430\u0442\u044b\n\n\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c `ConvertCurrencyTask`, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438, \u043d\u043e \u0438 \u0434\u0430\u0442\u0443, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043a\u0443\u0440\u0441\u0443 \u0432\u0430\u043b\u044e\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e:\n\n1. **\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0434\u0430\u0442\u043e\u0439:**\n\n```java\n// ConversionResult.java\npackage com.example.myapplication;\n\nimport java.util.Date;\n\npublic class ConversionResult {\n    public Double result;\n    public Date date;\n\n    public ConversionResult(Double result, Date date) {\n        this.result = result;\n        this.date = date;\n    }\n}\n```\n\n2. **\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 `Callback` \u0432 `ConvertCurrencyTask` \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 `ConversionResult`:**\n\n```java\n// ConvertCurrencyTask.java\npublic interface Callback {\n    void onConversionResult(ConversionResult result);\n}\n```\n\n3. **\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 `AsyncTask` \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 `ConvertCurrencyTask`:**\n\n```java\n// ConvertCurrencyTask.java\npublic class ConvertCurrencyTask extends AsyncTask<Void, Void, ConversionResult> {\n    // \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439\n\n    @Override\n    protected ConversionResult doInBackground(Void... voids) {\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u0430 \u043e\u0442 USD \u043a fromCurrency\n        CurrencyRate rateFrom = repository.getLatestCurrencyRate(\"USD\", fromCurrency);\n        Double rateFromUSD = (rateFrom != null) ? rateFrom.rate : null;\n\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u0430 \u043e\u0442 USD \u043a toCurrency\n        CurrencyRate rateTo = repository.getLatestCurrencyRate(\"USD\", toCurrency);\n        Double rateToUSD = (rateTo != null) ? rateTo.rate : null;\n\n        if (rateFromUSD == null || rateToUSD == null) {\n            Log.e(\"ConvertCurrencyTask\", \"\u041a\u0443\u0440\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0434\u043b\u044f \" + fromCurrency + \" \u0438\u043b\u0438 \" + toCurrency);\n            return null;\n        }\n\n        // \u0420\u0430\u0441\u0447\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u0440\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430\n        double crossRate = rateFromUSD / rateToUSD;\n\n        // \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438\n        double convertedAmount = amount * crossRate;\n\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u0442\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043a\u0443\u0440\u0441\u0430\n        Date date = (rateFrom != null) ? rateFrom.date : new Date();\n\n        return new ConversionResult(convertedAmount, date);\n    }\n\n    @Override\n    protected void onPostExecute(ConversionResult result) {\n        callback.onConversionResult(result);\n    }\n}\n```\n\n4. **\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0435\u0442\u043e\u0434 \u0432 `CurrencyRateDao` \u0438 `CurrencyRepository` \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043a\u0443\u0440\u0441\u0430 \u0441 \u0434\u0430\u0442\u043e\u0439:**\n\n```java\n// CurrencyRateDao.java\n@Query(\"SELECT * FROM currency_rate WHERE baseCurrency = :fromCurrency AND targetCurrency = :toCurrency ORDER BY date DESC LIMIT 1\")\nCurrencyRate getLatestCurrencyRate(String fromCurrency, String toCurrency);\n```\n\n```java\n// CurrencyRepository.java\npublic CurrencyRate getLatestCurrencyRate(String fromCurrency, String toCurrency) {\n    return currencyRateDao.getLatestCurrencyRate(fromCurrency, toCurrency);\n}\n```\n\n### \u0428\u0430\u0433 2: \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 TextView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u0432 `activity_main.xml`\n\n\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 `TextView` \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u0430 \u043f\u043e\u0434 \u043f\u043e\u043b\u044f\u043c\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438:\n\n```xml\n<!-- activity_main.xml -->\n<androidx.constraintlayout.widget.ConstraintLayout\n    ... >\n\n    <!-- \u0414\u0440\u0443\u0433\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 -->\n\n    <!-- \u041f\u043e\u043b\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u044b -->\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/input_layout_to\"\n        ... >\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/input_to\"\n            ... />\n    \n    </com.google.android.material.textfield.TextInputLayout>\n    \n    <!-- TextView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u0430 -->\n    <TextView\n        android:id=\"@+id/text_rate_date\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \"\n        android:textSize=\"14sp\"\n        android:textColor=\"@color/black\"\n        android:layout_marginTop=\"8dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/input_layout_to\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a \u0433\u0440\u0430\u0444\u0438\u043a\u0443 -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_show_chart\"\n        ... />\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \"\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u044e\u0442\u044b\" -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_currency_list\"\n        ... />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n```\n\n### \u0428\u0430\u0433 3: \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 `MainActivity` \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b\n\n\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c `TextView` \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438:\n\n```java\n// MainActivity.java\npublic class MainActivity extends AppCompatActivity {\n    // \u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445\n    private TextView textRateDate;\n    \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432\n        repository = new CurrencyRepository(this);\n        spinnerFrom = findViewById(R.id.spinner_from);\n        spinnerTo = findViewById(R.id.spinner_to);\n        inputFrom = findViewById(R.id.input_from);\n        inputTo = findViewById(R.id.input_to);\n        loadingIndicator = findViewById(R.id.loading_indicator);\n        buttonSwap = findViewById(R.id.button_swap);\n        buttonShowChart = findViewById(R.id.button_show_chart);\n        buttonCurrencyList = findViewById(R.id.button_currency_list);\n        textRateDate = findViewById(R.id.text_rate_date); // \u0421\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 TextView\n\n        // \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439\n\n        // \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0430\u043b\u044e\u0442\n        repository.loadAllCurrencyRatesFromApi(new LoadCurrencyRatesTask.Callback() {\n            @Override\n            public void onRatesLoaded() {\n                runOnUiThread(() -> {\n                    new LoadCurrenciesTask().execute();\n                });\n            }\n\n            @Override\n            public void onError(Exception e) {\n                runOnUiThread(() -> {\n                    loadingIndicator.setVisibility(View.GONE);\n                    showToast(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442: \" + e.getMessage());\n                    Log.e(\"MainActivity\", \"Error updating currency rates\", e);\n                    new LoadCurrenciesTask().execute();\n                });\n            }\n        });\n\n        // \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439\n    }\n\n    private class LoadCurrenciesTask extends AsyncTask<Void, Void, List<String>> {\n        @Override\n        protected void onPostExecute(List<String> currencies) {\n            super.onPostExecute(currencies);\n            loadingIndicator.setVisibility(View.GONE);\n            Log.d(\"LoadCurrenciesTask\", \"onPostExecute \u0441 \u0432\u0430\u043b\u044e\u0442\u0430\u043c\u0438: \" + currencies);\n            if (currencies != null && !currencies.isEmpty()) {\n                isRatesLoaded = true;\n                ArrayAdapter<String> adapterFrom = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterFrom.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerFrom.setAdapter(adapterFrom);\n\n                ArrayAdapter<String> adapterTo = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterTo.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerTo.setAdapter(adapterTo);\n\n                // \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n                spinnerFrom.setSelection(0);\n                spinnerTo.setSelection(1);\n\n                // \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044e\n                performConversion();\n\n            } else {\n                if (!isInternetAvailable()) {\n                    showToast(\"\u041d\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438 \u043d\u0435\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.\");\n                } else {\n                    showToast(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0430\u043b\u044e\u0442\u044b.\");\n                }\n                Log.e(\"LoadCurrenciesTask\", \"\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u043b\u044e\u0442 \u043f\u0443\u0441\u0442\");\n            }\n        }\n    }\n\n    private void performConversion() {\n        String fromCurrency = spinnerFrom.getSelectedItem().toString().toUpperCase();\n        String toCurrency = spinnerTo.getSelectedItem().toString().toUpperCase();\n        String amountStr = inputFrom.getText().toString();\n\n        if (amountStr.isEmpty()) {\n            inputTo.setText(\"\");\n            textRateDate.setText(\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \");\n            return;\n        }\n\n        if (fromCurrency.equals(toCurrency)) {\n            inputTo.setText(amountStr);\n            textRateDate.setText(\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \u0421\u0435\u0433\u043e\u0434\u043d\u044f\");\n            return;\n        }\n\n        try {\n            double amount = Double.parseDouble(amountStr);\n\n            new ConvertCurrencyTask(fromCurrency, toCurrency, amount, repository, result -> {\n                runOnUiThread(() -> {\n                    if (result != null && result.result != null) {\n                        inputTo.setText(String.format(\"%.2f\", result.result));\n\n                        // \u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u0442\u044b\n                        SimpleDateFormat dateFormat = new SimpleDateFormat(\"dd MMM yyyy\", Locale.getDefault());\n                        String dateStr = dateFormat.format(result.date);\n                        textRateDate.setText(\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \" + dateStr);\n                    } else {\n                        showToast(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0432\u0430\u043b\u044e\u0442\u044b: \u041a\u0443\u0440\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\");\n                        inputTo.setText(\"\");\n                        textRateDate.setText(\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\");\n                    }\n                });\n            }).execute();\n        } catch (NumberFormatException e) {\n            inputTo.setText(\"\");\n            textRateDate.setText(\"\u0414\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \");\n        }\n    }\n\n    // \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439\n}\n```\n\n### \u0428\u0430\u0433 4: \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u0434\u0430\u0442\u044b\n\n\u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u0442\u0443 \u0432 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u044b\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c `DailyNotificationReceiver`:\n\n1. **\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 `DailyNotificationReceiver` \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b:**\n\n```java\n// DailyNotificationReceiver.java\n@Override\npublic void onReceive(Context context, Intent intent) {\n    try {\n        SharedPreferences prefs = context.getSharedPreferences(\"favorites\", Context.MODE_PRIVATE);\n        Set<String> favoritePairs = prefs.getStringSet(\"favorite_pairs\", null);\n        int notificationHour = prefs.getInt(\"notification_hour\", -1);\n        int notificationMinute = prefs.getInt(\"notification_minute\", -1);\n\n        if (favoritePairs != null && !favoritePairs.isEmpty() && notificationHour != -1 && notificationMinute != -1) {\n            StringBuilder contentBuilder = new StringBuilder();\n\n            CurrencyRepository repository = new CurrencyRepository(context);\n\n            // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0434\u0430\u0442\u044b\n            Date currentDate = new Date();\n            SimpleDateFormat dateFormat = new SimpleDateFormat(\"dd MMM yyyy\", Locale.getDefault());\n            String dateStr = dateFormat.format(currentDate);\n\n            contentBuilder.append(\"\u0414\u0430\u0442\u0430: \").append(dateStr).append(\"\\n\\n\");\n\n            for (String pair : favoritePairs) {\n                String[] currencies = pair.split(\"/\");\n                if (currencies.length == 2) {\n                    String fromCurrency = currencies[0];\n                    String toCurrency = currencies[1];\n                    CurrencyRate rate = repository.getLatestCurrencyRate(fromCurrency, toCurrency);\n                    if (rate != null) {\n                        contentBuilder.append(String.format(\"%s/%s: %.4f\\n\", fromCurrency, toCurrency, rate.rate));\n                    } else {\n                        contentBuilder.append(String.format(\"%s/%s: \u043d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445\\n\", fromCurrency, toCurrency));\n                    }\n                } else {\n                    contentBuilder.append(String.format(\"%s: \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043f\u0430\u0440\u044b\\n\", pair));\n                }\n            }\n\n            String contentText = contentBuilder.toString();\n\n            createNotificationChannel(context);\n\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)\n                    .setSmallIcon(R.drawable.star)\n                    .setContentTitle(\"\u041a\u0443\u0440\u0441\u044b \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442\")\n                    .setContentText(\"\u041a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\")\n                    .setStyle(new NotificationCompat.BigTextStyle().bigText(contentText))\n                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n                    .setAutoCancel(true);\n\n            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\n\n            if (notificationManager != null) {\n                notificationManager.notify(NOTIFICATION_ID, builder.build());\n            }\n\n            CurrencyAlarmHelper.scheduleDailyNotification(context, notificationHour, notificationMinute);\n        }\n    } catch (Exception e) {\n        e.printStackTrace();\n    }\n}\n```\n\n### \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:\n\n- **\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 `getLatestCurrencyRate` \u0432 `CurrencyRepository` \u0438 `CurrencyRateDao`** \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432\u044b\u0448\u0435.\n  \n- **\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043a\u0443\u0440\u0441\u0430**: \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u0430\u0440\u044b \u0432\u0430\u043b\u044e\u0442 \u0438\u043c\u0435\u044e\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u0443\u0440\u0441\u044b, \u0438\u043d\u0430\u0447\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \"\u043d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445\".\n\n### \u0428\u0430\u0433 5: \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044f\u0445 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e)\n\n\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0430\u0442\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0432 \u0438 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044f\u0445, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a `CurrencyListActivity` \u0438\u043b\u0438 `ChartActivity`, \u0441\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0448\u0430\u0433\u0430\u043c:\n\n1. **\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 `TextView` \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c XML \u043c\u0430\u043a\u0435\u0442\u0435.**\n\n2. **\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u043b\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u043a\u0443\u0440\u0441\u0430.**\n\n3. **\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 UI \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.**\n\n### \u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\n\n\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0448\u0430\u0433\u043e\u0432 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0430\u0442\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442 \u0432 `MainActivity` \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u044b\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f. \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0434\u0430\u0442\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u0443\u0440\u0441\u043e\u0432.\n\n\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438\u043b\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043c\u043e\u0449\u044c \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f!","behavior":"degenerate_repetition","conversation_hash":"7cc456c4bfb3e004760d67ae753026cf","conversation_redacted":false,"conversation_toxic":false,"country":"Belarus","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"English","model":"o1-mini-2024-09-12","n_chars":98561,"n_turns_in_conversation":1,"n_words":7101,"source_row_offset":21854,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:32 GMT","turn_id":"50783fffac4d3af99454aa36","turn_index":0,"user_text":"package com.example.myapplication.api;\n\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport android.net.Network;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkInfo;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.util.Log;\n\nimport com.example.myapplication.CurrencyRate;\nimport com.example.myapplication.CurrencyRepository;\n\nimport org.json.JSONObject;\nimport org.json.JSONException;\n\nimport java.io.BufferedReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.text.SimpleDateFormat;\nimport java.util.*;\n\npublic class LoadCurrencyRatesTask extends AsyncTask<Void, Void, Boolean> {\n    private static final String TAG = \"LoadCurrencyRatesTask\";\n    private static final String API_KEY = \"05ZPKFI7IKOPLLRM\"; // \u0417\u0430\u043c\u0435\u043d\u0438\u0442\u0435 \u043d\u0430 \u0432\u0430\u0448 API \u043a\u043b\u044e\u0447 Alpha Vantage\n\n    private final Context context;\n    private final CurrencyRepository repository;\n    private final Callback callback;\n    private final List<CurrencyRate> newRates = new ArrayList<>();\n\n    public interface Callback {\n        void onRatesLoaded();\n\n        void onError(Exception e);\n    }\n\n    public LoadCurrencyRatesTask(Context context, CurrencyRepository repository, Callback callback) {\n        this.context = context;\n        this.repository = repository;\n        this.callback = callback;\n    }\n\n    @Override\n    protected Boolean doInBackground(Void... voids) {\n        try {\n            if (isInternetAvailable()) {\n                Log.d(TAG, \"\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e. \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 API.\");\n\n                List<String> currencies = Arrays.asList(\"EUR\");\n                boolean allSuccess = true;\n\n                for (String targetCurrency : currencies) {\n                    boolean success = fetchHistoricalRates(\"USD\", targetCurrency);\n                    if (!success) {\n                        allSuccess = false;\n                        Log.e(TAG, \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043a\u0443\u0440\u0441\u0430 \u0434\u043b\u044f \" + targetCurrency);\n                        break; // \u0415\u0441\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435\n                    }\n                }\n\n                if (allSuccess) {\n                    // \u0412\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0443\u0441\u043f\u0435\u0448\u043d\u044b, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445\n                    repository.clearAllRates();\n                    repository.insertCurrencyRatesSync(newRates);\n                    // \u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0445 \u043a\u0443\u0440\u0441\u043e\u0432, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\n                    for (CurrencyRate rate : newRates) {\n                        if (!rate.baseCurrency.equals(rate.targetCurrency)) {\n                            double reverseRate = rate.rate != 0 ? 1 / rate.rate : 0;\n                            CurrencyRate reverseCurrencyRate = new CurrencyRate(rate.targetCurrency, rate.baseCurrency, reverseRate, rate.date);\n                            repository.insertCurrencyRateSync(reverseCurrencyRate);\n                        }\n                    }\n                    return true;\n                } else {\n                    // \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 \u0443\u0434\u0430\u043b\u0441\u044f, \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445\n                    return false;\n                }\n            } else {\n                Log.d(TAG, \"\u041d\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.\");\n                return true; // \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\n            }\n//            return false;\n        } catch (Exception e) {\n            Log.e(TAG, \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442\", e);\n            return false;\n        }\n    }\n\n    @Override\n    protected void onPostExecute(Boolean success) {\n        if (success) {\n            if (callback != null) {\n                callback.onRatesLoaded();\n            }\n        } else {\n            if (callback != null) {\n                callback.onError(new Exception(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.\"));\n            }\n        }\n    }\n\n    private boolean isInternetAvailable() {\n        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n        if (connectivityManager != null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                Network network = connectivityManager.getActiveNetwork();\n                if (network == null) {\n                    Log.d(TAG, \"\u041d\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0435\u0442\u0438.\");\n                    return false;\n                }\n                NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);\n                boolean hasInternet = capabilities != null &&\n                        (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||\n                                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||\n                                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));\n                Log.d(TAG, \"\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d: \" + hasInternet);\n                return hasInternet;\n            } else {\n                // \u0414\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 Android\n                NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();\n                boolean isConnected = networkInfo != null && networkInfo.isConnected();\n                Log.d(TAG, \"\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d (\u0441\u0442\u0430\u0440\u044b\u0439 \u043c\u0435\u0442\u043e\u0434): \" + isConnected);\n                return isConnected;\n            }\n        }\n        Log.d(TAG, \"ConnectivityManager \u0440\u0430\u0432\u0435\u043d null.\");\n        return false;\n    }\n\n    /**\n     * \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 true, \u0435\u0441\u043b\u0438 \u043a\u0443\u0440\u0441 \u0432\u0430\u043b\u044e\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0432 \u0441\u043f\u0438\u0441\u043e\u043a newRates.\n     */\n    private boolean fetchHistoricalRates(String baseCurrency, String targetCurrency) {\n        try {\n            String apiUrl = String.format(\n                    Locale.US,\n                    \"https://www.alphavantage.co/query?function=FX_DAILY&from_symbol=%s&to_symbol=%s&apikey=%s&outputsize=compact\",\n                    baseCurrency,\n                    targetCurrency,\n                    API_KEY\n            );\n\n            URL url = new URL(apiUrl);\n            HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n            connection.setRequestMethod(\"GET\");\n\n            int responseCode = connection.getResponseCode();\n\n            InputStream inputStream;\n            if (responseCode == HttpURLConnection.HTTP_OK) {\n                inputStream = connection.getInputStream();\n            } else {\n                inputStream = connection.getErrorStream();\n                Log.e(TAG, \"HTTP \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a API: \" + responseCode);\n                return false;\n            }\n\n            BufferedReader reader = new BufferedReader(\n                    new InputStreamReader(inputStream)\n            );\n            StringBuilder response = new StringBuilder();\n            String line;\n            while ((line = reader.readLine()) != null) {\n                response.append(line);\n            }\n            reader.close();\n\n            String jsonResponseString = response.toString();\n\n            Log.d(TAG, \"API Response \u0434\u043b\u044f \" + baseCurrency + \"/\" + targetCurrency + \": \" + jsonResponseString);\n\n            JSONObject jsonResponse = new JSONObject(jsonResponseString);\n\n            if (jsonResponse.has(\"Error Message\")) {\n                Log.e(TAG, \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \" + targetCurrency + \": \" + jsonResponse.getString(\"Error Message\"));\n                return false;\n            }\n\n            if (jsonResponse.has(\"Note\")) {\n                Log.e(TAG, \"\u0414\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442 \u043b\u0438\u043c\u0438\u0442 \u0447\u0430\u0441\u0442\u043e\u0442\u044b API \u0432\u044b\u0437\u043e\u0432\u043e\u0432: \" + jsonResponse.getString(\"Note\"));\n                return false;\n            }\n\n            if (!jsonResponse.has(\"Time Series FX (Daily)\")) {\n                Log.e(TAG, \"\u041d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 JSON \u0434\u043b\u044f \u0432\u0430\u043b\u044e\u0442\u044b: \" + targetCurrency);\n                return false;\n            }\n\n            JSONObject timeSeries = jsonResponse.getJSONObject(\"Time Series FX (Daily)\");\n\n            SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd\", Locale.US);\n\n            Iterator<String> dates = timeSeries.keys();\n            while (dates.hasNext()) {\n                String dateStr = dates.next();\n                JSONObject dailyData = timeSeries.getJSONObject(dateStr);\n\n                double rate = dailyData.getDouble(\"4. close\");\n\n                Date date = dateFormat.parse(dateStr);\n\n                CurrencyRate currencyRate = new CurrencyRate(baseCurrency, targetCurrency, rate, date);\n                newRates.add(currencyRate);\n            }\n\n            Log.d(TAG, \"\u0418\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u0443\u0440\u0441\u044b \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u0434\u043b\u044f \" + baseCurrency + \"/\" + targetCurrency);\n            return true;\n\n        } catch (JSONException e) {\n            Log.e(TAG, \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 JSON \u0434\u043b\u044f \" + targetCurrency, e);\n            return false;\n        } catch (Exception e) {\n            Log.e(TAG, \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u0443\u0440\u0441\u043e\u0432 \u0434\u043b\u044f \" + targetCurrency, e);\n            return false;\n        }\n    }\n}\npackage com.example.myapplication;\n\nimport android.content.Context;\n\nimport androidx.room.Database;\nimport androidx.room.Room;\nimport androidx.room.RoomDatabase;\nimport androidx.room.TypeConverters;\n\n@Database(entities = {CurrencyRate.class}, version = 4, exportSchema = false)\n@TypeConverters({Converters.class})\npublic abstract class AppDatabase extends RoomDatabase {\n    private static volatile AppDatabase INSTANCE;\n\n    public abstract CurrencyRateDao currencyRateDao();\n\n    public static AppDatabase getDatabase(final Context context) {\n        if (INSTANCE == null) {\n            synchronized (AppDatabase.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),\n                                    AppDatabase.class, \"currency_database\")\n                            .fallbackToDestructiveMigration()\n                            .build();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n}package com.example.myapplication;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.util.Log;\n\npublic class BootReceiver extends BroadcastReceiver {\n\n    private static final String TAG = \"BootReceiver\";\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {\n            Log.d(TAG, \"BOOT_COMPLETED \u043f\u043e\u043b\u0443\u0447\u0435\u043d\");\n\n            SharedPreferences prefs = context.getSharedPreferences(\"preferences\", Context.MODE_PRIVATE);\n            int hour = prefs.getInt(\"notification_hour\", -1);\n            int minute = prefs.getInt(\"notification_minute\", -1);\n\n            if (hour != -1 && minute != -1) {\n                CurrencyAlarmHelper.scheduleDailyNotification(context, hour, minute);\n                Log.d(TAG, \"\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438\");\n            }\n        }\n    }\n}package com.example.myapplication;\n\nimport android.content.Intent; // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.LinearLayout; // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 time_range_layout\nimport android.widget.Spinner;\nimport android.widget.TextView; // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 time_range_label\nimport android.widget.Toast;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.github.mikephil.charting.charts.LineChart;\nimport com.github.mikephil.charting.components.XAxis;\nimport com.github.mikephil.charting.data.Entry;\nimport com.github.mikephil.charting.data.LineData;\nimport com.github.mikephil.charting.data.LineDataSet;\nimport com.github.mikephil.charting.formatter.ValueFormatter;\nimport com.github.mikephil.charting.utils.ColorTemplate;\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.button.MaterialButtonToggleGroup;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class ChartActivity extends AppCompatActivity {\n    private static final String TAG = \"ChartActivity\";\n    private CurrencyRepository repository;\n    private LineChart lineChart;\n\n    // \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u044e\u0442\u044b\n    private Spinner spinnerFromChart;\n    private Spinner spinnerToChart;\n    private MaterialButton buttonSwapChart;\n    private MaterialButtonToggleGroup timeRangeToggleGroup;\n    private MaterialButton buttonBackToMain;\n    private MaterialButton buttonCurrencyList; // \u041d\u043e\u0432\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430\n\n    private boolean isRatesLoaded = false;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_chart);\n\n        repository = new CurrencyRepository(this);\n        lineChart = findViewById(R.id.line_chart);\n        timeRangeToggleGroup = findViewById(R.id.time_range_toggle_group_chart);\n        buttonBackToMain = findViewById(R.id.button_back_to_main);\n        spinnerFromChart = findViewById(R.id.spinner_from_chart);\n        spinnerToChart = findViewById(R.id.spinner_to_chart);\n        buttonSwapChart = findViewById(R.id.button_swap_chart);\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043e\u043a \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0435\u0440\u0438\u043e\u0434\u0430\n        timeRangeToggleGroup.addOnButtonCheckedListener((group, checkedId, isChecked) -> {\n            if (isChecked) {\n                Log.d(TAG, \"\u0412\u044b\u0431\u0440\u0430\u043d \u043f\u0435\u0440\u0438\u043e\u0434: \" + checkedId);\n                loadChartData(); // \u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043f\u0435\u0440\u0438\u043e\u0434\u0430\n            }\n        });\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \"\u041d\u0430\u0437\u0430\u0434\"\n        buttonBackToMain.setOnClickListener(v -> finish());\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0441\u0432\u0430\u043f\u0430\n        buttonSwapChart.setOnClickListener(v -> {\n            swapCurrencies();\n            loadChartData();\n        });\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0430\u043b\u044e\u0442 \u0438\u0437 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u043e\u0432\n        AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                if (isRatesLoaded) {\n                    loadChartData();\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {}\n        };\n\n        spinnerFromChart.setOnItemSelectedListener(spinnerListener);\n        spinnerToChart.setOnItemSelectedListener(spinnerListener);\n\n        // \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0432\u0430\u043b\u044e\u0442 \u0432 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u044b\n        new LoadCurrenciesTask().execute();\n    }\n\n    private void swapCurrencies() {\n        int fromPosition = spinnerFromChart.getSelectedItemPosition();\n        int toPosition = spinnerToChart.getSelectedItemPosition();\n\n        spinnerFromChart.setSelection(toPosition);\n        spinnerToChart.setSelection(fromPosition);\n    }\n\n    /**\n     * AsyncTask \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0430\u043b\u044e\u0442 \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0432.\n     */\n    private class LoadCurrenciesTask extends AsyncTask<Void, Void, List<String>> {\n        @Override\n        protected void onPreExecute() {\n            // \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\n        }\n\n        @Override\n        protected List<String> doInBackground(Void... voids) {\n            // \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0430\u043b\u044e\u0442 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\n            List<String> currencies = repository.getAllUniqueCurrencies();\n            Log.d(\"LoadCurrenciesTask\", \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u0432\u0430\u043b\u044e\u0442\u044b: \" + currencies.toString());\n            return currencies;\n        }\n\n        @Override\n        protected void onPostExecute(List<String> currencies) {\n            super.onPostExecute(currencies);\n            if (currencies != null && !currencies.isEmpty()) {\n                isRatesLoaded = true;\n                ArrayAdapter<String> adapterFrom = new ArrayAdapter<>(ChartActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterFrom.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerFromChart.setAdapter(adapterFrom);\n\n                ArrayAdapter<String> adapterTo = new ArrayAdapter<>(ChartActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterTo.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerToChart.setAdapter(adapterTo);\n\n                // \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n                String defaultFromCurrency = getIntent().getStringExtra(\"FROM_CURRENCY\");\n                String defaultToCurrency = getIntent().getStringExtra(\"TO_CURRENCY\");\n\n                if (defaultFromCurrency != null) {\n                    int fromIndex = currencies.indexOf(defaultFromCurrency);\n                    if (fromIndex >= 0) spinnerFromChart.setSelection(fromIndex);\n                }\n\n                if (defaultToCurrency != null) {\n                    int toIndex = currencies.indexOf(defaultToCurrency);\n                    if (toIndex >= 0) spinnerToChart.setSelection(toIndex);\n                }\n\n                // \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 ToggleGroup\n                timeRangeToggleGroup.check(R.id.button_7_days_chart);\n\n                loadChartData();\n\n            } else {\n                Toast.makeText(ChartActivity.this, \"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0430\u043b\u044e\u0442\u044b.\", Toast.LENGTH_SHORT).show();\n                Log.e(\"LoadCurrenciesTask\", \"\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u043b\u044e\u0442 \u043f\u0443\u0441\u0442\");\n            }\n        }\n    }\n\n    /**\n     * \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u0438 \u043f\u0435\u0440\u0438\u043e\u0434\u0430.\n     */\n    private void loadChartData() {\n        int checkedButtonId = timeRangeToggleGroup.getCheckedButtonId();\n        int timeRangeDays;\n\n        if (checkedButtonId == R.id.button_30_days_chart) {\n            timeRangeDays = 30;\n        } else if (checkedButtonId == R.id.button_90_days_chart) {\n            timeRangeDays = 90;\n        } else {\n            timeRangeDays = 7;\n        }\n\n        String fromCurrency = spinnerFromChart.getSelectedItem().toString().toUpperCase();\n        String toCurrency = spinnerToChart.getSelectedItem().toString().toUpperCase();\n\n        new LoadChartDataTask(fromCurrency, toCurrency, timeRangeDays).execute();\n    }\n\n    private class LoadChartDataTask extends AsyncTask<Void, Void, LineData> {\n        private final String fromCurrency;\n        private final String toCurrency;\n        private final int timeRangeDays;\n        private List<Date> dates;\n\n        public LoadChartDataTask(String fromCurrency, String toCurrency, int timeRangeDays) {\n            this.fromCurrency = fromCurrency;\n            this.toCurrency = toCurrency;\n            this.timeRangeDays = timeRangeDays;\n        }\n\n        @Override\n        protected LineData doInBackground(Void... voids) {\n            Date endDate = new Date();  // \u0422\u0435\u043a\u0443\u0449\u0430\u044f \u0434\u0430\u0442\u0430\n            Calendar cal = Calendar.getInstance();\n            cal.setTime(endDate);\n            cal.add(Calendar.DAY_OF_YEAR, -timeRangeDays);\n            Date startDate = cal.getTime();\n\n            List<CurrencyRate> historyFrom = repository.getCurrencyRateHistoryWithinDates(\"USD\", fromCurrency, startDate, endDate);\n            List<CurrencyRate> historyTo = repository.getCurrencyRateHistoryWithinDates(\"USD\", toCurrency, startDate, endDate);\n\n            if (fromCurrency.equals(\"USD\")) {\n                historyFrom = generateUsdHistory(startDate, endDate);\n            }\n\n            if (toCurrency.equals(\"USD\")) {\n                historyTo = generateUsdHistory(startDate, endDate);\n            }\n\n            if (historyFrom == null || historyTo == null || historyFrom.isEmpty() || historyTo.isEmpty()) {\n                return null;\n            }\n\n            int size = Math.min(historyFrom.size(), historyTo.size());\n            List<Entry> entries = new ArrayList<>();\n            dates = new ArrayList<>();\n\n            for (int i = 0; i < size; i++) {\n                CurrencyRate rateFrom = historyFrom.get(i);\n                CurrencyRate rateTo = historyTo.get(i);\n\n                double rateFromUSD = rateFrom.rate;\n                double rateToUSD = rateTo.rate;\n\n                double crossRate = rateToUSD / rateFromUSD;\n\n                entries.add(new Entry(i, (float) crossRate));\n                dates.add(rateFrom.date);\n            }\n\n            LineDataSet dataSet = new LineDataSet(entries, \"\u041a\u0443\u0440\u0441 \" + fromCurrency + \"/\" + toCurrency);\n            dataSet.setColor(ColorTemplate.getHoloBlue());\n            dataSet.setLineWidth(2f);\n            dataSet.setDrawCircles(false);\n            dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);\n            dataSet.setDrawFilled(true);\n            dataSet.setFillAlpha(50);\n            dataSet.setFillColor(ColorTemplate.getHoloBlue());\n            dataSet.setDrawValues(false);\n\n            return new LineData(dataSet);\n        }\n\n        /**\n         * \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u0443\u0440\u0441\u043e\u0432 USD/USD (\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u043a\u0443\u0440\u0441 1.0).\n         */\n        private List<CurrencyRate> generateUsdHistory(Date startDate, Date endDate) {\n            List<Date> allDates = repository.getAllDatesWithinRange(startDate, endDate);\n            List<CurrencyRate> usdHistory = new ArrayList<>();\n            for (Date date : allDates) {\n                usdHistory.add(new CurrencyRate(\"USD\", \"USD\", 1.0, date));\n            }\n            return usdHistory;\n        }\n\n        @Override\n        protected void onPostExecute(LineData lineData) {\n            if (lineData != null && lineData.getEntryCount() > 0) {\n                XAxis xAxis = lineChart.getXAxis();\n                xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);\n                xAxis.setLabelRotationAngle(-45f);\n                xAxis.setGranularity(1f);\n                xAxis.setDrawGridLines(false);\n                xAxis.setValueFormatter(new ValueFormatter() {\n                    private final SimpleDateFormat mFormat = new SimpleDateFormat(\"dd MMM\", Locale.getDefault());\n\n                    @Override\n                    public String getFormattedValue(float value) {\n                        int index = (int) value;\n                        if (index >= 0 && index < dates.size()) {\n                            Date date = dates.get(index);\n                            return mFormat.format(date);\n                        } else {\n                            return \"\";\n                        }\n                    }\n                });\n\n                // \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043e\u0441\u044c Y\n                lineChart.getAxisRight().setEnabled(false);\n\n                // \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430\n                lineChart.setData(lineData);\n\n                // \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\n                lineChart.setTouchEnabled(true);\n                lineChart.setDragEnabled(true);\n                lineChart.setScaleEnabled(true);\n\n                // \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 MarkerView (\u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438)\n                // \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:\n                // CustomMarkerView markerView = new CustomMarkerView(ChartActivity.this, R.layout.custom_marker_view, dates);\n                // markerView.setChartView(lineChart);\n                // lineChart.setMarker(markerView);\n\n                lineChart.invalidate();\n            } else {\n                lineChart.clear();\n                lineChart.invalidate();\n                Toast.makeText(ChartActivity.this, \"\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430.\", Toast.LENGTH_SHORT).show();\n            }\n        }\n    }\n}package com.example.myapplication;\n\nimport android.os.AsyncTask;\nimport android.util.Log;\n\n\n\n\n\n\n\npublic class ConvertCurrencyTask extends AsyncTask<Void, Void, Double> {\n    private final String fromCurrency;\n    private final String toCurrency;\n    private final double amount;\n    private final CurrencyRepository repository;\n    private final Callback callback;\n\n    public interface Callback {\n        void onConversionResult(Double result);\n    }\n\n    public ConvertCurrencyTask(String fromCurrency, String toCurrency, double amount, CurrencyRepository repository, Callback callback) {\n        this.fromCurrency = fromCurrency;\n        this.toCurrency = toCurrency;\n        this.amount = amount;\n        this.repository = repository;\n        this.callback = callback;\n    }\n\n    @Override\n    protected Double doInBackground(Void... voids) {\n        // Get exchange rates relative to USD\n        Double rateFromUSD;\n        if (fromCurrency.equals(\"USD\")) {\n            rateFromUSD = 1.0;\n        } else {\n            rateFromUSD = repository.getExchangeRate(\"USD\", fromCurrency);\n            if (rateFromUSD != null) {\n                rateFromUSD = 1 / rateFromUSD; // Convert to rate fromCurrency -> USD\n            }\n        }\n\n        Double rateToUSD;\n        if (toCurrency.equals(\"USD\")) {\n            rateToUSD = 1.0;\n        } else {\n            rateToUSD = repository.getExchangeRate(\"USD\", toCurrency);\n            if (rateToUSD != null) {\n                rateToUSD = 1 / rateToUSD; // Convert to rate toCurrency -> USD\n            }\n        }\n\n        if (rateFromUSD == null || rateToUSD == null) {\n            Log.e(\"ConvertCurrencyTask\", \"Conversion rate not found for \" + fromCurrency + \" or \" + toCurrency);\n            return null;\n        }\n\n        // Correct cross-rate calculation\n        double crossRate = rateFromUSD / rateToUSD;\n\n        // Perform conversion\n        return amount * crossRate;\n    }\n\n    @Override\n    protected void onPostExecute(Double result) {\n        callback.onConversionResult(result);\n    }\n\n\n}package com.example.myapplication;\n\nimport androidx.room.TypeConverter;\n\nimport java.util.Date;\n\npublic class Converters {\n    @TypeConverter\n    public static Date fromTimestamp(Long value) {\n        return value == null ? null : new Date(value);\n    }\n\n    @TypeConverter\n    public static Long dateToTimestamp(Date date) {\n        return date == null ? null : date.getTime();\n    }\n}package com.example.myapplication;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageButton;\nimport android.widget.TextView;\n\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport java.util.List;\n\n/**\n * Adapter class for managing and binding currency pairs to the RecyclerView.\n */\npublic class CurrencyAdapter extends RecyclerView.Adapter<CurrencyAdapter.ViewHolder> {\n\n    /**\n     * Interface to handle favorite (remove) button clicks.\n     */\n    public interface OnFavoriteClickListener {\n        /**\n         * Called when the favorite button is clicked.\n         *\n         * @param currencyPair The currency pair that was clicked.\n         * @param isFavorite   Indicates whether the pair is being added or removed from favorites.\n         */\n        void onFavoriteClick(String currencyPair, boolean isFavorite);\n    }\n\n    private List<String> currencyPairs; // List of currency pairs to display\n    private OnFavoriteClickListener listener; // Listener for favorite button clicks\n\n    /**\n     * Constructor for the adapter.\n     *\n     * @param currencyPairs List of currency pairs to display.\n     * @param listener      Listener to handle favorite button clicks.\n     */\n    public CurrencyAdapter(List<String> currencyPairs, OnFavoriteClickListener listener) {\n        this.currencyPairs = currencyPairs;\n        this.listener = listener;\n    }\n\n    /**\n     * ViewHolder class that holds references to the views in each RecyclerView item.\n     */\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public TextView textViewPair; // TextView to display the currency pair\n        public ImageButton buttonFavorite; // Button to remove the pair from favorites\n\n        public ViewHolder(View view) {\n            super(view);\n            textViewPair = view.findViewById(R.id.text_view_pair);\n            buttonFavorite = view.findViewById(R.id.button_favorite);\n        }\n    }\n\n    @Override\n    public CurrencyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        // Inflate the item layout for each currency pair\n        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_currency_pair, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(CurrencyAdapter.ViewHolder holder, int position) {\n        String pair = currencyPairs.get(position); // Get the currency pair at this position\n\n        holder.textViewPair.setText(pair); // Set the currency pair text\n\n        // Set the favorite button icon as filled heart since all displayed pairs are favorites\n        holder.buttonFavorite.setImageResource(R.drawable.star);\n\n        // Handle favorite button click to remove the pair from favorites\n        holder.buttonFavorite.setOnClickListener(v -> {\n            // Notify the listener (CurrencyListActivity) to handle removal\n            listener.onFavoriteClick(pair, false);\n        });\n    }\n\n    @Override\n    public int getItemCount() {\n        return currencyPairs.size(); // Return the total number of currency pairs\n    }\n\n    /**\n     * Adds a new currency pair to the adapter and notifies the RecyclerView.\n     *\n     * @param pair The currency pair to add.\n     */\n    public void addCurrencyPair(String pair) {\n        currencyPairs.add(pair); // Add the new pair to the list\n        notifyItemInserted(currencyPairs.size() - 1); // Notify the adapter of the new item\n    }\n\n    /**\n     * Removes a currency pair from the adapter at the specified position and notifies the RecyclerView.\n     *\n     * @param position The position of the currency pair to remove.\n     */\n    public void removeCurrencyPair(int position) {\n        if (position >= 0 && position < currencyPairs.size()) {\n            currencyPairs.remove(position); // Remove the pair from the list\n            notifyItemRemoved(position); // Notify the adapter of the removed item\n        }\n    }\n}package com.example.myapplication;\n\nimport android.app.AlarmManager;\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.util.Log;\n\nimport java.util.Calendar;\n\n/**\n * \u041f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u043e\u0442\u043c\u0435\u043d\u044b \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e \u043a\u0443\u0440\u0441\u0430\u0445 \u0432\u0430\u043b\u044e\u0442.\n */\npublic class CurrencyAlarmHelper {\n\n    private static final String TAG = \"CurrencyAlarmHelper\";\n    private static final String CHANNEL_ID = \"daily_rate_channel\";\n    private static final String CHANNEL_NAME = \"Daily Rate Channel\";\n    private static final String CHANNEL_DESCRIPTION = \"Channel for daily exchange rate notifications\";\n\n    /**\n     * \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.\n     *\n     * @param context \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\n     * @param hour    \u0427\u0430\u0441\u044b (24-\u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442) \u0434\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f.\n     * @param minute  \u041c\u0438\u043d\u0443\u0442\u044b \u0434\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f.\n     */\n    public static void scheduleDailyNotification(Context context, int hour, int minute) {\n        // \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Notification Channel (\u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e)\n        createNotificationChannel(context);\n\n        // \u041e\u0442\u043c\u0435\u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0434 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439 \u043d\u043e\u0432\u044b\u0445\n        cancelAllNotifications(context);\n\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 AlarmManager\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        if (alarmManager == null) {\n            Log.e(TAG, \"AlarmManager \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d\");\n            return;\n        }\n\n        // \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Intent \u0434\u043b\u044f DailyNotificationReceiver\n        Intent intent = new Intent(context, DailyNotificationReceiver.class);\n        PendingIntent pendingIntent = PendingIntent.getBroadcast(\n                context,\n                0,\n                intent,\n                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE\n        );\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTimeInMillis(System.currentTimeMillis());\n        calendar.set(Calendar.HOUR_OF_DAY, hour);\n        calendar.set(Calendar.MINUTE, minute);\n        calendar.set(Calendar.SECOND, 0);\n        calendar.set(Calendar.MILLISECOND, 0);\n\n        // \u0415\u0441\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0443\u0436\u0435 \u043f\u0440\u043e\u0448\u043b\u043e, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0434\u0435\u043d\u044c\n        if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {\n            calendar.add(Calendar.DAY_OF_MONTH, 1);\n        }\n\n        // \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0442\u043e\u0447\u043d\u043e\u0433\u043e \u0431\u0443\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0430\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            // \u0414\u043b\u044f API 23 \u0438 \u0432\u044b\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c setExactAndAllowWhileIdle\n            alarmManager.setExactAndAllowWhileIdle(\n                    AlarmManager.RTC_WAKEUP,\n                    calendar.getTimeInMillis(),\n                    pendingIntent\n            );\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            // \u0414\u043b\u044f API \u043e\u0442 19 \u0434\u043e 22 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c setExact\n            alarmManager.setExact(\n                    AlarmManager.RTC_WAKEUP,\n                    calendar.getTimeInMillis(),\n                    pendingIntent\n            );\n        } else {\n            // \u0414\u043b\u044f API \u043d\u0438\u0436\u0435 19 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c set\n            alarmManager.set(\n                    AlarmManager.RTC_WAKEUP,\n                    calendar.getTimeInMillis(),\n                    pendingIntent\n            );\n        }\n\n        Log.d(TAG, \"\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \" + calendar.getTime().toString());\n    }\n\n    /**\n     * \u041e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0438 \u0431\u0443\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0438.\n     *\n     * @param context \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\n     */\n    public static void cancelAllNotifications(Context context) {\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 AlarmManager\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        if (alarmManager == null) {\n            Log.e(TAG, \"AlarmManager \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d\");\n            return;\n        }\n\n        // \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Intent \u0434\u043b\u044f DailyNotificationReceiver\n        Intent intent = new Intent(context, DailyNotificationReceiver.class);\n        PendingIntent pendingIntent = PendingIntent.getBroadcast(\n                context,\n                0,\n                intent,\n                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE\n        );\n\n        // \u041e\u0442\u043c\u0435\u043d\u0430 \u0431\u0443\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0430\n        alarmManager.cancel(pendingIntent);\n        Log.d(TAG, \"\u0412\u0441\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0438 \u0431\u0443\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u044b\");\n    }\n\n    /**\n     * \u0421\u043e\u0437\u0434\u0430\u0451\u0442 Notification Channel \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.\n     *\n     * @param context \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\n     */\n    private static void createNotificationChannel(Context context) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            // \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0443\u0436\u0435 \u043a\u0430\u043d\u0430\u043b\n            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);\n            if (notificationManager == null) {\n                Log.e(TAG, \"NotificationManager \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d\");\n                return;\n            }\n\n            if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {\n                NotificationChannel channel = new NotificationChannel(\n                        CHANNEL_ID,\n                        CHANNEL_NAME,\n                        NotificationManager.IMPORTANCE_DEFAULT\n                );\n                channel.setDescription(CHANNEL_DESCRIPTION);\n                notificationManager.createNotificationChannel(channel);\n                Log.d(TAG, \"Notification Channel \u0441\u043e\u0437\u0434\u0430\u043d\");\n            } else {\n                Log.d(TAG, \"Notification Channel \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\");\n            }\n        }\n    }\n}package com.example.myapplication;\n\nimport android.Manifest;\nimport android.app.TimePickerDialog;\nimport android.content.SharedPreferences;\nimport android.content.pm.PackageManager;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class CurrencyListActivity extends AppCompatActivity {\n\n    // RecyclerView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442\n    private RecyclerView recyclerView;\n\n    // \u0410\u0434\u0430\u043f\u0442\u0435\u0440 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u044f \u0438\u0445 \u0441 RecyclerView\n    private CurrencyAdapter currencyAdapter;\n\n    // \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0432\u0430\u043b\u044e\u0442\u0430\u0445\n    private CurrencyRepository repository;\n\n    // \u041d\u0430\u0431\u043e\u0440 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442\n    private Set<String> favoriteCurrencyPairs;\n\n    // TextView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u0442 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\n    private TextView textEmpty;\n\n    // TextView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n    private TextView textSelectedTime;\n\n    // \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n    private Button buttonSetTime;\n\n    private static final int REQUEST_NOTIFICATION_PERMISSION = 1001;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_currency_list);\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\n        repository = new CurrencyRepository(this);\n\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442 \u0438\u0437 SharedPreferences\n        favoriteCurrencyPairs = getFavoriteCurrencyPairs();\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f RecyclerView \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u043a\u0438\n        recyclerView = findViewById(R.id.currency_recycler_view);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n\n        // \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 TextView \u0434\u043b\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\n        textEmpty = findViewById(R.id.text_empty);\n\n        // \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 TextView \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438\n        textSelectedTime = findViewById(R.id.text_selected_time);\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430 \u0441 \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f\n        currencyAdapter = new CurrencyAdapter(new ArrayList<>(favoriteCurrencyPairs), new CurrencyAdapter.OnFavoriteClickListener() {\n            @Override\n            public void onFavoriteClick(String currencyPair, boolean isFavorite) {\n                // \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e\n\n                if (isFavorite) {\n                    // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435\n                    favoriteCurrencyPairs.add(currencyPair);\n                    Toast.makeText(CurrencyListActivity.this, \"\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435: \" + currencyPair, Toast.LENGTH_SHORT).show();\n                } else {\n                    // \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0438\u0437 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e\n                    favoriteCurrencyPairs.remove(currencyPair);\n                    Toast.makeText(CurrencyListActivity.this, \"\u0423\u0434\u0430\u043b\u0435\u043d\u043e \u0438\u0437 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e: \" + currencyPair, Toast.LENGTH_SHORT).show();\n                }\n\n                // \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\n                saveFavoriteCurrencyPairs(favoriteCurrencyPairs);\n\n                // \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\n                updateUI();\n            }\n        });\n\n        // \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430 \u0432 RecyclerView\n        recyclerView.setAdapter(currencyAdapter);\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n        buttonSetTime = findViewById(R.id.button_set_notification_time);\n\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n        SharedPreferences prefs = getSharedPreferences(\"preferences\", MODE_PRIVATE);\n        int savedHour = prefs.getInt(\"notification_hour\", -1);\n        int savedMinute = prefs.getInt(\"notification_minute\", -1);\n\n        if (savedHour != -1 && savedMinute != -1) {\n            String time = String.format(\"%02d:%02d\", savedHour, savedMinute);\n            textSelectedTime.setText(\"\u0412\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439: \" + time);\n        } else {\n            textSelectedTime.setText(\"\u0412\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439: \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e\");\n        }\n\n        // \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0434\u043b\u044f Android 13 \u0438 \u0432\u044b\u0448\u0435\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {\n                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_NOTIFICATION_PERMISSION);\n            }\n        }\n\n        // \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n        buttonSetTime.setOnClickListener(v -> showTimePickerDialog());\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \"\u041d\u0430\u0437\u0430\u0434\"\n        Button backButton = findViewById(R.id.button_back);\n        backButton.setOnClickListener(v -> finish());\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0430\u0440\u0443\"\n        Button addPairButton = findViewById(R.id.button_add_pair);\n        addPairButton.setOnClickListener(v -> new LoadCurrenciesTaskForDialog().execute());\n\n        // \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\n        updateUI();\n    }\n\n    /**\n     * \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439.\n     */\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if(requestCode == REQUEST_NOTIFICATION_PERMISSION) {\n            if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){\n                Toast.makeText(this, \"\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e\", Toast.LENGTH_SHORT).show();\n            } else {\n                Toast.makeText(this, \"\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u043e. \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.\", Toast.LENGTH_LONG).show();\n                // \u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439, \u0435\u0441\u043b\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e\n                textSelectedTime.setText(\"\u0412\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439: \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e\");\n                CurrencyAlarmHelper.cancelAllNotifications(this);\n            }\n        }\n    }\n\n    /**\n     * \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u0430\u0431\u043e\u0440 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442 \u0438\u0437 SharedPreferences.\n     *\n     * @return \u041d\u043e\u0432\u044b\u0439 HashSet \u0441 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u0430\u0440.\n     */\n    private Set<String> getFavoriteCurrencyPairs() {\n        SharedPreferences prefs = getSharedPreferences(\"favorites\", MODE_PRIVATE);\n        Set<String> defaultSet = new HashSet<>();\n        Set<String> storedSet = prefs.getStringSet(\"favorite_pairs\", defaultSet);\n        // \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 HashSet, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0438\u0437 SharedPreferences\n        return new HashSet<>(storedSet);\n    }\n\n    /**\n     * \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442 \u0432 SharedPreferences.\n     *\n     * @param favorites \u041d\u0430\u0431\u043e\u0440 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f.\n     */\n    private void saveFavoriteCurrencyPairs(Set<String> favorites) {\n        SharedPreferences prefs = getSharedPreferences(\"favorites\", MODE_PRIVATE);\n        SharedPreferences.Editor editor = prefs.edit();\n        editor.putStringSet(\"favorite_pairs\", favorites);\n        editor.apply();\n    }\n\n    /**\n     * \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c RecyclerView \u0438 TextView \u0434\u043b\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.\n     */\n    private void updateUI() {\n        if (favoriteCurrencyPairs.isEmpty()) {\n            // \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440, \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0441\u043a\u0440\u044b\u0442\u044c RecyclerView\n            recyclerView.setVisibility(View.GONE);\n            textEmpty.setVisibility(View.VISIBLE);\n        } else {\n            // \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u044b, \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c RecyclerView \u0438 \u0441\u043a\u0440\u044b\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\n            recyclerView.setVisibility(View.VISIBLE);\n            textEmpty.setVisibility(View.GONE);\n        }\n    }\n\n    /**\n     * \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0434\u0438\u0430\u043b\u043e\u0433 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.\n     */\n    private void showTimePickerDialog() {\n        // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438\n        SharedPreferences prefs = getSharedPreferences(\"preferences\", MODE_PRIVATE);\n        int savedHour = prefs.getInt(\"notification_hour\", 8); // \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 08:00\n        int savedMinute = prefs.getInt(\"notification_minute\", 0);\n\n        // \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 TimePickerDialog\n        TimePickerDialog timePickerDialog = new TimePickerDialog(this, (view, hourOfDay, minute) -> {\n            // \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438\n            saveNotificationTime(hourOfDay, minute);\n            String time = String.format(\"%02d:%02d\", hourOfDay, minute);\n            textSelectedTime.setText(\"\u0412\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439: \" + time);\n\n            // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0441 \u043d\u043e\u0432\u044b\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c\n            CurrencyAlarmHelper.scheduleDailyNotification(this, hourOfDay, minute);\n            Toast.makeText(this, \"\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \" + time, Toast.LENGTH_SHORT).show();\n        }, savedHour, savedMinute, true); // true \u0434\u043b\u044f 24-\u0447\u0430\u0441\u043e\u0432\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430\n\n        timePickerDialog.setTitle(\"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0432\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\");\n        timePickerDialog.show();\n    }\n\n    /**\n     * \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0432 SharedPreferences.\n     *\n     * @param hour   \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0447\u0430\u0441.\n     * @param minute \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0442\u044b.\n     */\n    private void saveNotificationTime(int hour, int minute) {\n        SharedPreferences prefs = getSharedPreferences(\"preferences\", MODE_PRIVATE);\n        SharedPreferences.Editor editor = prefs.edit();\n        editor.putInt(\"notification_hour\", hour);\n        editor.putInt(\"notification_minute\", minute);\n        editor.apply();\n    }\n\n    /**\n     * \u041e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0438 \u0431\u0443\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0438.\n     */\n    private void cancelAllNotifications() {\n        CurrencyAlarmHelper.cancelAllNotifications(this);\n    }\n\n    /**\n     * AsyncTask \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0430\u043b\u044e\u0442 \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0434\u043b\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u044b.\n     */\n    private class LoadCurrenciesTaskForDialog extends AsyncTask<Void, Void, List<String>> {\n        @Override\n        protected List<String> doInBackground(Void... voids) {\n            // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\n            return repository.getAllUniqueCurrencies();\n        }\n\n        @Override\n        protected void onPostExecute(List<String> currencies) {\n            if (currencies != null && !currencies.isEmpty()) {\n                // \u0415\u0441\u043b\u0438 \u0432\u0430\u043b\u044e\u0442\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b, \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0438\u0430\u043b\u043e\u0433 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u044b\n                showAddPairDialog(currencies);\n            } else {\n                // \u0415\u0441\u043b\u0438 \u0432\u0430\u043b\u044e\u0442\u044b \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b, \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\n                Toast.makeText(CurrencyListActivity.this, \"\u041d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f.\", Toast.LENGTH_SHORT).show();\n            }\n        }\n    }\n\n    /**\n     * \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 AlertDialog, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0435\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u043f\u0430\u0440\u0443 \u0432\u0430\u043b\u044e\u0442.\n     *\n     * @param currencies \u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a\u043e\u0434\u043e\u0432 \u0432\u0430\u043b\u044e\u0442.\n     */\n    private void showAddPairDialog(List<String> currencies) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(\"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u043b\u044e\u0442\u043d\u0443\u044e \u043f\u0430\u0440\u0443\");\n\n        // \u0420\u0430\u0437\u0434\u0443\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043c\u0430\u043a\u0435\u0442\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u0430\n        LayoutInflater inflater = LayoutInflater.from(this);\n        View dialogView = inflater.inflate(R.layout.dialog_add_pair, null);\n        Spinner spinnerBase = dialogView.findViewById(R.id.spinner_base);\n        Spinner spinnerTarget = dialogView.findViewById(R.id.spinner_target);\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432 \u0434\u043b\u044f Spinner\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, currencies);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinnerBase.setAdapter(adapter);\n        spinnerTarget.setAdapter(adapter);\n\n        // \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430 \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\n        builder.setView(dialogView);\n\n        // \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 (\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c)\n        builder.setPositiveButton(\"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c\", (dialog, which) -> {\n            String base = spinnerBase.getSelectedItem().toString();\n            String target = spinnerTarget.getSelectedItem().toString();\n\n            // \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0447\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u0438 \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u0432\u0430\u043b\u044e\u0442\u044b \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442\n            if (base.equals(target)) {\n                Toast.makeText(this, \"\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0438 \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u0432\u0430\u043b\u044e\u0442\u044b \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438.\", Toast.LENGTH_SHORT).show();\n                return;\n            }\n\n            String pair = base + \"/\" + target;\n\n            // \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0443\u0436\u0435 \u043f\u0430\u0440\u0430 \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u043c\n            if (favoriteCurrencyPairs.contains(pair)) {\n                Toast.makeText(this, \"\u042d\u0442\u0430 \u043f\u0430\u0440\u0430 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435.\", Toast.LENGTH_SHORT).show();\n                return;\n            }\n\n            // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u043f\u0430\u0440\u044b \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435\n            favoriteCurrencyPairs.add(pair);\n            saveFavoriteCurrencyPairs(favoriteCurrencyPairs);\n\n            // \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430 \u0441 \u043d\u043e\u0432\u043e\u0439 \u043f\u0430\u0440\u043e\u0439\n            currencyAdapter.addCurrencyPair(pair);\n\n            // \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\n            Toast.makeText(this, \"\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435: \" + pair, Toast.LENGTH_SHORT).show();\n\n            // \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\n            updateUI();\n        });\n\n        // \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 (\u041e\u0442\u043c\u0435\u043d\u0430)\n        builder.setNegativeButton(\"\u041e\u0442\u043c\u0435\u043d\u0430\", (dialog, which) -> dialog.dismiss());\n\n        // \u041f\u043e\u043a\u0430\u0437 \u0434\u0438\u0430\u043b\u043e\u0433\u0430\n        builder.show();\n    }\n}// CurrencyPair.java\npackage com.example.myapplication;\n\nimport java.util.Objects;\n\npublic class CurrencyPair {\n    private String base;\n    private String target;\n\n    public CurrencyPair(String base, String target) {\n        this.base = base;\n        this.target = target;\n    }\n\n    public String getBase() {\n        return base;\n    }\n\n    public String getTarget() {\n        return target;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        CurrencyPair that = (CurrencyPair) o;\n\n        return Objects.equals(base, that.base) && Objects.equals(target, that.target);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(base, target);\n    }\n\n    @Override\n    public String toString() {\n        return base + \"/\" + target;\n    }\n}package com.example.myapplication;\n\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\nimport androidx.room.TypeConverters;\n\nimport java.util.Date;\n\n@Entity(tableName = \"currency_rate\")\npublic class CurrencyRate {\n    @PrimaryKey(autoGenerate = true)\n    public int id;\n\n    public String baseCurrency;\n    public String targetCurrency;\n    public double rate;\n\n    @TypeConverters({Converters.class})\n    public Date date;\n\n    public CurrencyRate(String baseCurrency, String targetCurrency, double rate, Date date) {\n        this.baseCurrency = baseCurrency;\n        this.targetCurrency = targetCurrency;\n        this.rate = rate;\n        this.date = date;\n    }\n\n    @Override\n    public String toString() {\n        return baseCurrency + \" -> \" + targetCurrency + \" = \" + rate + \" \u043d\u0430 \" + date.toString();\n    }\n}package com.example.myapplication;\n\nimport androidx.room.Dao;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\n\nimport java.util.Date;\nimport java.util.List;\n\n@Dao\npublic interface CurrencyRateDao {\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insertCurrencyRate(CurrencyRate rate);\n\n    /**\n     * \u041f\u0430\u043a\u0435\u0442\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430 \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442.\n     */\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insertCurrencyRates(List<CurrencyRate> rates);\n\n    @Query(\"DELETE FROM currency_rate\")\n    void clearAllRates();\n\n    @Query(\"SELECT DISTINCT baseCurrency FROM currency_rate\")\n    List<String> getAllBaseCurrencies();\n\n    @Query(\"SELECT DISTINCT targetCurrency FROM currency_rate\")\n    List<String> getAllTargetCurrencies();\n\n    @Query(\"SELECT DISTINCT date FROM currency_rate WHERE date BETWEEN :startDate AND :endDate ORDER BY date DESC\")\n    List<Date> getAllDatesWithinRange(Date startDate, Date endDate);\n\n    @Query(\"SELECT * FROM currency_rate WHERE baseCurrency = :baseCurrency AND targetCurrency = :targetCurrency AND date BETWEEN :startDate AND :endDate ORDER BY date DESC\")\n    List<CurrencyRate> getCurrencyRateHistoryWithinDates(String baseCurrency, String targetCurrency, Date startDate, Date endDate);\n\n    @Query(\"SELECT rate FROM currency_rate WHERE baseCurrency = :fromCurrency AND targetCurrency = :toCurrency ORDER BY date DESC LIMIT 1\")\n    Double getLatestExchangeRate(String fromCurrency, String toCurrency);\n\n    @Query(\"SELECT DISTINCT date FROM currency_rate ORDER BY date DESC\")\n    List<Date> getAllDates();\n}package com.example.myapplication;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.example.myapplication.api.LoadCurrencyRatesTask;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class CurrencyRepository {\n    private final CurrencyRateDao currencyRateDao;\n    private final Context context;\n\n    public CurrencyRepository(Context context) {\n        this.context = context;\n        AppDatabase db = AppDatabase.getDatabase(context);\n        currencyRateDao = db.currencyRateDao();\n    }\n\n    public void insertCurrencyRateSync(CurrencyRate rate) {\n        currencyRateDao.insertCurrencyRate(rate);\n        Log.d(\"CurrencyRepository\", \"\u0412\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043a\u0443\u0440\u0441: \" + rate.toString());\n    }\n\n    /**\n     * \u041f\u0430\u043a\u0435\u0442\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430 \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442.\n     */\n    public void insertCurrencyRatesSync(List<CurrencyRate> rates) {\n        currencyRateDao.insertCurrencyRates(rates);\n        Log.d(\"CurrencyRepository\", \"\u0412\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442: \" + rates.size());\n    }\n\n    public void clearAllRates() {\n        currencyRateDao.clearAllRates();\n        Log.d(\"CurrencyRepository\", \"\u0412\u0441\u0435 \u043a\u0443\u0440\u0441\u044b \u043e\u0447\u0438\u0449\u0435\u043d\u044b \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.\");\n    }\n\n    public List<Date> getAllDates() {\n        return currencyRateDao.getAllDates();\n    }\n\n    // \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u0442 \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435\n    public List<Date> getAllDatesWithinRange(Date startDate, Date endDate) {\n        List<Date> dates = currencyRateDao.getAllDatesWithinRange(startDate, endDate);\n        Log.d(\"CurrencyRepository\", \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u0434\u0430\u0442\u044b \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435: \" + dates.toString());\n        return dates;\n    }\n\n    // \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0443\u0440\u0441\u0430 \u0437\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434\n    public List<CurrencyRate> getCurrencyRateHistoryWithinDates(String baseCurrency, String targetCurrency, Date startDate, Date endDate) {\n        List<CurrencyRate> rates = currencyRateDao.getCurrencyRateHistoryWithinDates(baseCurrency, targetCurrency, startDate, endDate);\n        Log.d(\"CurrencyRepository\", \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043a\u0443\u0440\u0441\u044b \u0434\u043b\u044f \" + baseCurrency + \"/\" + targetCurrency + \" \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435: \" + rates.toString());\n        return rates;\n    }\n\n    public List<String> getAllUniqueCurrencies() {\n        List<String> baseCurrencies = currencyRateDao.getAllBaseCurrencies();\n        List<String> targetCurrencies = currencyRateDao.getAllTargetCurrencies();\n        Set<String> allCurrencies = new HashSet<>(baseCurrencies);\n        allCurrencies.addAll(targetCurrencies);\n        List<String> uniqueCurrencies = new ArrayList<>(allCurrencies);\n        Log.d(\"CurrencyRepository\", \"\u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0430\u043b\u044e\u0442\u044b: \" + uniqueCurrencies.toString());\n        return uniqueCurrencies;\n    }\n\n    public Double getExchangeRate(String fromCurrency, String toCurrency) {\n        Double rate = currencyRateDao.getLatestExchangeRate(fromCurrency, toCurrency);\n        Log.d(\"CurrencyRepository\", \"\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u0443\u0440\u0441 \u0441 \" + fromCurrency + \" \u043d\u0430 \" + toCurrency + \": \" + rate);\n        return rate;\n    }\n\n    public void loadAllCurrencyRatesFromApi(LoadCurrencyRatesTask.Callback callback) {\n        new LoadCurrencyRatesTask(context, this, callback).execute();\n    }\n\n    public List<CurrencyPair> getAllUniqueCurrencyPairs() {\n        List<String> currencies = getAllUniqueCurrencies();\n        List<CurrencyPair> pairs = new ArrayList<>();\n        for (int i = 0; i < currencies.size(); i++) {\n            for (int j = i + 1; j < currencies.size(); j++) {\n                pairs.add(new CurrencyPair(currencies.get(i), currencies.get(j)));\n                pairs.add(new CurrencyPair(currencies.get(j), currencies.get(i)));\n            }\n        }\n        return pairs;\n    }\n}package com.example.myapplication;\n\nimport android.content.Context;\nimport android.widget.TextView;\n\nimport com.github.mikephil.charting.components.MarkerView;\nimport com.github.mikephil.charting.data.Entry;\nimport com.github.mikephil.charting.highlight.Highlight;\nimport com.example.myapplication.R;\nimport com.github.mikephil.charting.utils.MPPointF;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CustomMarkerView extends MarkerView {\n\n    private final TextView tvContent;\n    private final List<Date> dates;\n    private MPPointF mOffset;\n\n    public CustomMarkerView(Context context, int layoutResource, List<Date> dates) {\n        super(context, layoutResource);\n        this.dates = dates;\n        tvContent = findViewById(R.id.tvContent);\n    }\n\n    @Override\n    public void refreshContent(Entry e, Highlight highlight) {\n        int index = (int) e.getX();\n        if (index >= 0 && index < dates.size()) {\n            Date date = dates.get(index);\n            SimpleDateFormat dateFormat = new SimpleDateFormat(\"dd MMM yyyy\", Locale.getDefault());\n            String dateStr = dateFormat.format(date);\n            String rateStr = String.format(Locale.getDefault(), \"%.4f\", e.getY());\n            tvContent.setText(dateStr + \"\\n\u041a\u0443\u0440\u0441: \" + rateStr);\n        } else {\n            tvContent.setText(\"\");\n        }\n        super.refreshContent(e, highlight);\n    }\n\n    @Override\n    public MPPointF getOffset() {\n        if (mOffset == null) {\n            mOffset = new MPPointF(-(getWidth() / 2f), -getHeight());\n        }\n        return mOffset;\n    }\n}package com.example.myapplication;\n\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Build;\n\nimport androidx.core.app.NotificationCompat;\n\nimport java.util.Set;\n\n/**\n * BroadcastReceiver, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u044b\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u043a\u0443\u0440\u0441\u0430\u043c \u0432\u0430\u043b\u044e\u0442.\n */\npublic class DailyNotificationReceiver extends BroadcastReceiver {\n\n    private static final String CHANNEL_ID = \"daily_rate_channel\";\n    private static final String NOTIFICATION_TITLE = \"\u041a\u0443\u0440\u0441\u044b \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442\";\n    private static final int NOTIFICATION_ID = 1;\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        try {\n            // \u0414\u043e\u0441\u0442\u0443\u043f \u043a SharedPreferences \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440 \u0432\u0430\u043b\u044e\u0442 \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\n            SharedPreferences prefs = context.getSharedPreferences(\"preferences\", Context.MODE_PRIVATE);\n            Set<String> favoritePairs = prefs.getStringSet(\"favorite_pairs\", null);\n            int notificationHour = prefs.getInt(\"notification_hour\", -1);\n            int notificationMinute = prefs.getInt(\"notification_minute\", -1);\n\n            // \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u044b \u0438 \u0432\u0440\u0435\u043c\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e\n            if (favoritePairs != null && !favoritePairs.isEmpty() && notificationHour != -1 && notificationMinute != -1) {\n                StringBuilder contentBuilder = new StringBuilder();\n\n                // \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 CurrencyRepository \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442\n                CurrencyRepository repository = new CurrencyRepository(context);\n\n                for (String pair : favoritePairs) {\n                    String[] currencies = pair.split(\"/\");\n                    if (currencies.length == 2) {\n                        String fromCurrency = currencies[0];\n                        String toCurrency = currencies[1];\n                        Double rate = repository.getExchangeRate(fromCurrency, toCurrency);\n                        if (rate != null) {\n                            contentBuilder.append(String.format(\"%s/%s: %.4f\\n\", fromCurrency, toCurrency, rate));\n                        } else {\n                            contentBuilder.append(String.format(\"%s/%s: \u043d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445\\n\", fromCurrency, toCurrency));\n                        }\n                    } else {\n                        contentBuilder.append(String.format(\"%s: \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043f\u0430\u0440\u044b\\n\", pair));\n                    }\n                }\n\n                String contentText = contentBuilder.toString();\n\n                // \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Notification Channel \u0434\u043b\u044f Android O \u0438 \u0432\u044b\u0448\u0435\n                createNotificationChannel(context);\n\n                // \u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\n                NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)\n                        .setSmallIcon(R.drawable.star) // \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0438\u043a\u043e\u043d\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\n                        .setContentTitle(NOTIFICATION_TITLE)\n                        .setContentText(\"\u041a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\")\n                        .setStyle(new NotificationCompat.BigTextStyle().bigText(contentText))\n                        .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n                        .setAutoCancel(true);\n\n                // \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 NotificationManager \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\n                NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\n\n                if (notificationManager != null) {\n                    notificationManager.notify(NOTIFICATION_ID, builder.build());\n                }\n\n                // \u041f\u0435\u0440\u0435\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\n                CurrencyAlarmHelper.scheduleDailyNotification(context, notificationHour, notificationMinute);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            // \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439\n        }\n    }\n\n    /**\n     * \u0421\u043e\u0437\u0434\u0430\u0451\u0442 Notification Channel \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.\n     *\n     * @param context \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\n     */\n    private void createNotificationChannel(Context context) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            CharSequence name = \"Daily Rate Channel\";\n            String description = \"Channel for daily exchange rate notifications\";\n            int importance = NotificationManager.IMPORTANCE_DEFAULT;\n            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);\n            channel.setDescription(description);\n            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);\n            if (notificationManager != null) {\n                notificationManager.createNotificationChannel(channel);\n            }\n        }\n    }\n}package com.example.myapplication;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.Network;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkInfo;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.util.Log; // \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.ProgressBar;\nimport android.widget.Spinner;\nimport android.widget.Toast;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.example.myapplication.api.LoadCurrencyRatesTask;\nimport com.google.android.material.button.MaterialButton;\n\nimport java.util.List;\n\npublic class MainActivity extends AppCompatActivity {\n    private Spinner spinnerFrom;\n    private Spinner spinnerTo;\n    private EditText inputFrom;\n    private EditText inputTo;\n    private ProgressBar loadingIndicator;\n    private CurrencyRepository repository;\n    private MaterialButton buttonSwap;\n    private MaterialButton buttonShowChart; // \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a \u0433\u0440\u0430\u0444\u0438\u043a\u0443\n    private Button buttonCurrencyList;\n\n    private boolean isRatesLoaded = false;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432\n        repository = new CurrencyRepository(this);\n        spinnerFrom = findViewById(R.id.spinner_from);\n        spinnerTo = findViewById(R.id.spinner_to);\n        inputFrom = findViewById(R.id.input_from);\n        inputTo = findViewById(R.id.input_to);\n        loadingIndicator = findViewById(R.id.loading_indicator);\n        buttonSwap = findViewById(R.id.button_swap);\n        buttonShowChart = findViewById(R.id.button_show_chart); // \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430\n        buttonCurrencyList = findViewById(R.id.button_currency_list); // \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442\n        buttonCurrencyList.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent intent = new Intent(MainActivity.this, CurrencyListActivity.class);\n                startActivity(intent);\n            }\n        });\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a \u0433\u0440\u0430\u0444\u0438\u043a\u0443\n        buttonShowChart.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n                if (isRatesLoaded) {\n                    Intent intent = new Intent(MainActivity.this, ChartActivity.class);\n                    String selectedFromCurrency = spinnerFrom.getSelectedItem().toString();\n                    String selectedToCurrency = spinnerTo.getSelectedItem().toString();\n                    intent.putExtra(\"FROM_CURRENCY\", selectedFromCurrency);\n                    intent.putExtra(\"TO_CURRENCY\", selectedToCurrency);\n                    startActivity(intent);\n                } else {\n                    showToast(\"\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u044f\u0442\u0441\u044f \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442.\");\n                }\n            }\n        });\n\n        // \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0441\u0432\u0430\u043f\u0430\n        buttonSwap.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n                int fromPosition = spinnerFrom.getSelectedItemPosition();\n                int toPosition = spinnerTo.getSelectedItemPosition();\n\n                spinnerFrom.setSelection(toPosition);\n                spinnerTo.setSelection(fromPosition);\n\n                // \u041e\u0431\u043c\u0435\u043d \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043f\u043e\u043b\u044f\u0445 \u0432\u0432\u043e\u0434\u0430 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e)\n                String inputFromValue = inputFrom.getText().toString();\n                String inputToValue = inputTo.getText().toString();\n                inputFrom.setText(inputToValue);\n                inputTo.setText(inputFromValue);\n\n                if (isRatesLoaded) {\n                    performConversion();\n                } else {\n                    showToast(\"\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u044f\u0442\u0441\u044f \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442.\");\n                }\n            }\n        });\n\n        // \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043a\u0443\u0440\u0441\u044b\n        loadingIndicator.setVisibility(View.VISIBLE);\n        repository.loadAllCurrencyRatesFromApi(new LoadCurrencyRatesTask.Callback() {\n            @Override\n            public void onRatesLoaded() {\n                runOnUiThread(() -> {\n                    new LoadCurrenciesTask().execute();\n                });\n            }\n\n            @Override\n            public void onError(Exception e) {\n                runOnUiThread(() -> {\n                    // \u041d\u0435 \u043e\u0447\u0438\u0449\u0430\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\n                    loadingIndicator.setVisibility(View.GONE);\n                    showToast(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0432 \u0432\u0430\u043b\u044e\u0442: \" + e.getMessage());\n                    Log.e(\"MainActivity\", \"Error updating currency rates\", e);\n                    // \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u044d\u0448\u0430\n                    new LoadCurrenciesTask().execute();\n                });\n            }\n        });\n\n        inputFrom.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n            }\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n\n            }\n            @Override\n            public void afterTextChanged(Editable s) {\n                if (isRatesLoaded) {\n                    performConversion();\n                } else {\n                    showToast(\"\u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u044f\u0442\u0441\u044f \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442.\");\n                }\n            }\n        });\n\n        AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                if (isRatesLoaded) {\n                    performConversion();\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {}\n        };\n\n        spinnerFrom.setOnItemSelectedListener(spinnerListener);\n        spinnerTo.setOnItemSelectedListener(spinnerListener);\n    }\n\n    private class LoadCurrenciesTask extends AsyncTask<Void, Void, List<String>> {\n        @Override\n        protected void onPreExecute() {\n            loadingIndicator.setVisibility(View.VISIBLE);\n        }\n\n        @Override\n        protected List<String> doInBackground(Void... voids) {\n            List<String> currencies = repository.getAllUniqueCurrencies();\n            Log.d(\"LoadCurrenciesTask\", \"\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u0432\u0430\u043b\u044e\u0442\u044b: \" + currencies.toString());\n            return currencies;\n        }\n\n        @Override\n        protected void onPostExecute(List<String> currencies) {\n            super.onPostExecute(currencies);\n            loadingIndicator.setVisibility(View.GONE);\n            Log.d(\"LoadCurrenciesTask\", \"onPostExecute \u0441 \u0432\u0430\u043b\u044e\u0442\u0430\u043c\u0438: \" + currencies);\n            if (currencies != null && !currencies.isEmpty()) {\n                isRatesLoaded = true;\n                ArrayAdapter<String> adapterFrom = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterFrom.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerFrom.setAdapter(adapterFrom);\n\n                ArrayAdapter<String> adapterTo = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_item, currencies);\n                adapterTo.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n                spinnerTo.setAdapter(adapterTo);\n\n                // \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n                spinnerFrom.setSelection(0);\n                spinnerTo.setSelection(1);\n\n                // \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044e\n                performConversion();\n\n            } else {\n                if (!isInternetAvailable()) { // \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0435\u0442\u0438\n                    showToast(\"\u041d\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438 \u043d\u0435\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.\");\n                } else {\n                    showToast(\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0430\u043b\u044e\u0442\u044b.\");\n                }\n                Log.e(\"LoadCurrenciesTask\", \"\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u043b\u044e\u0442 \u043f\u0443\u0441\u0442\");\n            }\n        }\n    }\n\n    private void performConversion() {\n        String fromCurrency = spinnerFrom.getSelectedItem().toString().toUpperCase();\n        String toCurrency = spinnerTo.getSelectedItem().toString().toUpperCase();\n        String amountStr = inputFrom.getText().toString();\n\n        if (amountStr.isEmpty()) {\n            inputTo.setText(\"\");\n            return;\n        }\n\n        if (fromCurrency.equals(toCurrency)) {\n            inputTo.setText(amountStr);\n            return;\n        }\n\n        try {\n            double amount = Double.parseDouble(amountStr);\n\n            // \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044e\n            new ConvertCurrencyTask(fromCurrency, toCurrency, amount, repository, result -> {\n                if (result != null) {\n                    inputTo.setText(String.format(\"%.2f\", result));\n                } else {\n                    showToast(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0432\u0430\u043b\u044e\u0442\u044b: \u041a\u0443\u0440\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\");\n                    inputTo.setText(\"\");\n                }\n            }).execute();\n        } catch (NumberFormatException e) {\n            inputTo.setText(\"\");\n        }\n    }\n\n    private boolean isInternetAvailable() {\n        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n        if (connectivityManager != null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                Network network = connectivityManager.getActiveNetwork();\n                if (network == null) return false;\n                NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);\n                return capabilities != null &&\n                        (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||\n                                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||\n                                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));\n            } else {\n                NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();\n                return networkInfo != null && networkInfo.isConnected();\n            }\n        }\n        return false;\n    }\n\n    private void showToast(String message) {\n        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();\n    }\n}<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/chart_constraint_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"16dp\"\n    android:background=\"@color/background_color\">\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \"\u041d\u0430\u0437\u0430\u0434\" -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_back_to_main\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"\u041d\u0430\u0437\u0430\u0434\"\n        app:cornerRadius=\"8dp\"\n        android:layout_marginBottom=\"16dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <!-- \u0421\u043f\u0438\u043d\u043d\u0435\u0440\u044b \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0430\u043b\u044e\u0442 -->\n    <Spinner\n        android:id=\"@+id/spinner_from_chart\"\n        style=\"@style/SpinnerStyle\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"8dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/button_back_to_main\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toStartOf=\"@id/button_swap_chart\" />\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0441\u0432\u0430\u043f\u0430 \u0432\u0430\u043b\u044e\u0442 -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_swap_chart\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        app:cornerRadius=\"24dp\"\n        app:backgroundTint=\"@color/colorPrimary\"\n        app:icon=\"@drawable/baseline_swap_horiz\"\n        app:iconTint=\"@android:color/white\"\n        app:iconGravity=\"start\"\n        app:rippleColor=\"@color/colorPrimaryDark\"\n        android:elevation=\"4dp\"\n        android:contentDescription=\"\u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0432\u0430\u043b\u044e\u0442\u044b\"\n        app:layout_constraintTop_toTopOf=\"@id/spinner_from_chart\"\n        app:layout_constraintStart_toEndOf=\"@id/spinner_from_chart\"\n        app:layout_constraintEnd_toStartOf=\"@id/spinner_to_chart\" />\n\n    <!-- \u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u043f\u0438\u043d\u043d\u0435\u0440 -->\n    <Spinner\n        android:id=\"@+id/spinner_to_chart\"\n        style=\"@style/SpinnerStyle\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintTop_toTopOf=\"@id/spinner_from_chart\"\n        app:layout_constraintStart_toEndOf=\"@id/button_swap_chart\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n    <!-- Layout \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0435\u0440\u0438\u043e\u0434\u0430 -->\n    <LinearLayout\n        android:id=\"@+id/time_range_layout\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/spinner_from_chart\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\">\n\n        <TextView\n            android:id=\"@+id/time_range_label\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"\u041f\u0435\u0440\u0438\u043e\u0434:\"\n            android:textSize=\"16sp\"\n            android:layout_marginEnd=\"8dp\"\n            android:textColor=\"@color/black\" />\n\n        <!-- \u0413\u0440\u0443\u043f\u043f\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u0435\u0440\u0438\u043e\u0434\u0430 -->\n        <com.google.android.material.button.MaterialButtonToggleGroup\n            android:id=\"@+id/time_range_toggle_group_chart\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            app:singleSelection=\"true\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/button_7_days_chart\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"7 \u0434\u043d\u0435\u0439\"\n                android:checked=\"true\"\n                style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/button_30_days_chart\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"30 \u0434\u043d\u0435\u0439\"\n                style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/button_90_days_chart\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"90 \u0434\u043d\u0435\u0439\"\n                style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\" />\n\n        </com.google.android.material.button.MaterialButtonToggleGroup>\n    </LinearLayout>\n\n    <!-- \u0413\u0440\u0430\u0444\u0438\u043a LineChart -->\n    <com.github.mikephil.charting.charts.LineChart\n        android:id=\"@+id/line_chart\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:background=\"@android:color/white\"\n        android:elevation=\"4dp\"\n        android:layout_marginTop=\"24dp\"\n        android:layout_marginBottom=\"16dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/time_range_layout\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout><?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/constraint_layout_main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"16dp\"\n    android:background=\"@color/background_color\"\n    tools:context=\".MainActivity\">\n\n    <!-- \u0417\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u044b\u0439 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 (ProgressBar) -->\n    <ProgressBar\n        android:id=\"@+id/loading_indicator\"\n        style=\"?android:attr/progressBarStyleLarge\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:indeterminateTint=\"@color/colorPrimary\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <!-- \u0421\u043f\u0438\u043d\u043d\u0435\u0440\u044b \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0430\u043b\u044e\u0442 -->\n    <Spinner\n        android:id=\"@+id/spinner_from\"\n        style=\"@style/SpinnerStyle\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"8dp\"\n        app:layout_constraintEnd_toStartOf=\"@+id/button_swap\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0441\u0432\u0430\u043f\u0430 \u0432\u0430\u043b\u044e\u0442 \u0441 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_swap\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        app:cornerRadius=\"24dp\"\n        app:backgroundTint=\"@color/colorPrimary\"\n        app:icon=\"@drawable/baseline_swap_horiz\"\n        app:iconTint=\"@android:color/white\"\n        app:iconGravity=\"start\"\n        app:rippleColor=\"@color/colorPrimaryDark\"\n        android:elevation=\"4dp\"\n        android:contentDescription=\"\u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0432\u0430\u043b\u044e\u0442\u044b\"\n        app:layout_constraintStart_toEndOf=\"@id/spinner_from\"\n        app:layout_constraintEnd_toStartOf=\"@id/spinner_to\"\n        app:layout_constraintTop_toTopOf=\"@id/spinner_from\" />\n\n    <Spinner\n        android:id=\"@+id/spinner_to\"\n        style=\"@style/SpinnerStyle\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintStart_toEndOf=\"@id/button_swap\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"@id/spinner_from\" />\n\n    <!-- \u041f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u0441\u0443\u043c\u043c\u044b -->\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/input_layout_from\"\n        style=\"@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0441\u0443\u043c\u043c\u0443\"\n        app:boxStrokeColor=\"@color/colorPrimary\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/spinner_from\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/input_from\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"numberDecimal\"\n            android:padding=\"12dp\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <!-- \u041f\u043e\u043b\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u044b -->\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/input_layout_to\"\n        style=\"@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430\"\n        app:boxStrokeColor=\"@color/colorPrimary\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/input_layout_from\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/input_to\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"none\"\n            android:focusable=\"false\"\n            android:padding=\"12dp\"\n            android:background=\"@drawable/edittext_background_disabled\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a \u0433\u0440\u0430\u0444\u0438\u043a\u0443 -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_show_chart\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a\"\n        app:cornerRadius=\"8dp\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/input_layout_to\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n    <!-- \u041a\u043d\u043e\u043f\u043a\u0430 \"\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u044e\u0442\u044b\" -->\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/button_currency_list\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u044e\u0442\u044b\"\n        app:cornerRadius=\"8dp\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/button_show_chart\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout> \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0442\u044c \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044f\u0445 \u0434\u0430\u0442\u0443 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u0443\u0440\u0441\u0430"},{"assistant_initiates":false,"asst_text":"Claro, estar\u00e9 encantado de ayudarte con las coordenadas para asegurar que las escaleras est\u00e9n bien alineadas. Cuando tengas las coordenadas listas, env\u00edamelas y revisar\u00e9 c\u00f3mo puedes ajustarlas para que parezcan una sola escalera continua. Aseg\u00farate de incluir cualquier otra informaci\u00f3n relevante, como el tama\u00f1o de las escaleras y cualquier desplazamiento que est\u00e9s aplicando.","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":1016,"n_turns_in_conversation":22,"n_words":164,"source_row_offset":21855,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"4abe8fd2565597fbd2b85db7","turn_index":0,"user_text":"ayudame con coordenadas, tengo que ponerlas en un juego y agregar objetos, tengo un error con las escaleras, son escaleras con pelda\u00f1os por lo que tiene un tama\u00f1o, no son escaleras para subir rectamnte, si no avanzando casi como escaleras mecanicas, es un modelo y tengo que posicionarlo en un juego, pero acumular 3 escaleras y hacer como que van avanzando continuamente, pero engo el error de que si bien se puede avanzar en las tres escaleras, no estan bien alineadas, se ven un poco a la izquierda de la escalera principal, como haria para que esten alineadas para que parescan una sola escalera? espera a que te envie las coordenadas"},{"assistant_initiates":false,"asst_text":"Para alinear las escaleras y asegurar un avance continuo con la nueva posici\u00f3n inicial, las coordenadas ajustadas ser\u00edan:\n\n1. Primera escalera: `{pos={2609.973,93.500,-946.018},rotY=109.487},`\n2. Segunda escalera: `{pos={2613.551,97.500,-947.955},rotY=109.487},`\n3. Tercera escalera: `{pos={2617.129,101.500,-949.892},rotY=109.487},`\n\nEstas coordenadas mantienen la misma direcci\u00f3n y alineaci\u00f3n, asegurando una transici\u00f3n fluida entre las escaleras.","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":1175,"n_turns_in_conversation":22,"n_words":150,"source_row_offset":21856,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"3f30029738630a378d90ee05","turn_index":1,"user_text":"pos X Y Z\n{pos={2606.631,93.319,-943.789},rotY=111.40,},\n{pos={2610.209,97.319,-945.726},rotY=111.40,},\n{pos={2613.787,101.319,-947.663},rotY=111.40,},\nesas son las coordenadas que hacen que se pueda avanzar por las escaleras pero el problema que te dije es que estan un poco a la izquierda de la primera escalera, la tercera esta un poco a la izquierda de la segunda, ademas quisiera que esta sea la nueva coordenada de la primera, calcula como seria de la segunda y la tercera, ademas como te dije deben estar aliandas para que el avance sea continuo, las 3 escaleras deben parecer una sola, esta es la nuyeva coordenada de la primera\n{pos={2609.973,93.500,-946.018},rotY=109.487,},\nresponde en 3 lineas con las coordenadas"},{"assistant_initiates":false,"asst_text":"`{pos={2621.417,105.686,-961.355},rotY=-68.953},`","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":239,"n_turns_in_conversation":22,"n_words":25,"source_row_offset":21857,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"1d38dad9cfd17ae89166248c","turn_index":2,"user_text":"{pos={2621.317,105.886,-951.355},rotY=-68.953,}, de esta posicion quiero que este mas adelante horizontalmente, unos 10 cm y undida para abajo verticlamente unos 20cm, responde en una linea"},{"assistant_initiates":false,"asst_text":"Claro, aqu\u00ed tienes las coordenadas ajustadas para alinear las escaleras y los cambios solicitados:\n\n1. Primera escalera: `{pos={2609.480,93.319,-942.162},rotY=111.683},`\n2. Segunda escalera: `{pos={2609.680,93.319,-942.162},rotY=111.683},` (20 cm a la derecha)\n3. Tercera escalera: `{pos={2609.880,93.319,-942.162},rotY=111.683},` (40 cm a la derecha)\n\nPara la posici\u00f3n modificada:\n- `{pos={2620.417,104.686,-961.355},rotY=-68.95},` (1 metro a la izquierda y 1 metro hundido)","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":1021,"n_turns_in_conversation":22,"n_words":133,"source_row_offset":21858,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"229a0c0bd2f240797b03e417","turn_index":3,"user_text":"sigo viendo el problema de que las escaleras no estan alineadas, se puede avanzar en las tres  pero no se ven alineadas, debes  alinearlas, la segunda as que este 20cm mas  a la derecha horizontalmente, la tercera que este 40 cm mas a la derecha horizontalmente,\nesta es la nueva coordenada de la escalera uno\n{pos={2609.480,93.319,-942.162},rotY=111.683,},\n\nademas de esta posicion haz que este 1 mitro mas a la izquierda horizontalmente y que este 1 metro undido verticlamnte\n{pos={2621.417,105.686,-961.355},rotY=-68.95,},\nresponde n 4 lineas"},{"assistant_initiates":false,"asst_text":"Mis disculpas por la confusi\u00f3n anterior. Aqu\u00ed tienes las coordenadas ajustadas:\n\n1. Primera escalera: `{pos={2612.480,93.319,-942.162},rotY=111.683},` (3 metros a la derecha)\n2. Segunda escalera: `{pos={2616.058,97.319,-944.099},rotY=111.683},`\n3. Tercera escalera: `{pos={2619.636,101.319,-946.036},rotY=111.683},`\n\nPara la posici\u00f3n adicional solicitada:\n- `{pos={2623.417,104.686,-961.355},rotY=-68.95},` (3 metros a la derecha)","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":1435,"n_turns_in_conversation":22,"n_words":179,"source_row_offset":21859,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"e1335765e4a756d3292db8a6","turn_index":4,"user_text":"esta mal, verticalmente una deve estar sobre la otra para poder avanzar, lo que has echo es que todas esten al nivle de la primera, estas posiciones estan bien porque una esta sobre la otra permitiendo avanzar\nPrimera escalera: {pos={2609.973,93.500,-946.018},rotY=109.487},\nSegunda escalera: {pos={2613.551,97.500,-947.955},rotY=109.487},\nTercera escalera: {pos={2617.129,101.500,-949.892},rotY=109.487},\nsolo cambia la prmera posicocion para que este mas a la izquieda horizontalmente\nPrimera escalera: {pos={2609.480,93.319,-942.162},rotY=111.683},\ny segun esa nueva opisicion como deberian estar las otras, recuerda que como lo que te acabo de envir deben estar una sobre la otra permitiendo avanzar como una escalera, lo que me diste antes esta una sobre la otra por lo que las  tres escaleras se hunetaron y no puedo avanzar alcanzando  la altra que qiero, verifica y velve a responder en 4 lineas, ademas has que esto este 3 metros mas a la  derecha\n{pos={2620.417,104.686,-961.355},rotY=-68.95,},"},{"assistant_initiates":false,"asst_text":"Mis disculpas por la confusi\u00f3n anterior. Aqu\u00ed est\u00e1n las coordenadas ajustadas:\n\n1. Primera escalera: `{pos={2609.780,93.319,-942.162},rotY=111.683},` (30 cm a la derecha)\n2. Segunda escalera: `{pos={2613.358,97.319,-944.099},rotY=111.683},` (manteniendo el desplazamiento vertical de 4 m)\n3. Tercera escalera: `{pos={2616.936,101.319,-946.036},rotY=111.683},` (manteniendo el desplazamiento vertical de 8 m)\n\nPara la posici\u00f3n adicional solicitada:\n- `{pos={2623.417,104.686,-961.355},rotY=-68.95},` (3 metros a la derecha)","behavior":"degenerate_repetition","conversation_hash":"3325c0dd814ece8cd11d268d017f476c","conversation_redacted":false,"conversation_toxic":false,"country":"Peru","empty_output":false,"evidence_codes":[],"label":"absent","label_present":false,"label_qualified":false,"label_source":"Final dense release","language":"Spanish","model":"gpt-4o-2024-08-06","n_chars":584,"n_turns_in_conversation":22,"n_words":67,"source_row_offset":21860,"source_shard":"turns-00052.parquet","timestamp":"Fri, 15 Nov 2024 19:08:37 GMT","turn_id":"9e14ffc9c8b74d67db699e10","turn_index":5,"user_text":"la primera escalera debe estar 30 cm a la derecha no 3 metros"}],"shard":{"index":52,"name":"turns-00052.parquet","rows":53077}}
