{"id":401607,"date":"2024-06-29T15:58:20","date_gmt":"2024-06-29T15:58:20","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=401607"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=401607","title":{"rendered":"<span>\u041a\u0430\u043a \u043c\u044b \u0443\u043b\u0443\u0447\u0448\u0430\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043e\u043d\u043b\u0430\u0439\u043d-\u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 \u043d\u0430 tvOS<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0412\u0430\u043b\u0435\u0440\u0438\u044f \u0420\u0443\u0431\u043b\u0435\u0432\u0441\u043a\u0430\u044f, \u044f iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043d\u043b\u0430\u0439\u043d-\u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 <a href=\"https:\/\/kion.ru\/home\">KION<\/a> \u0432 <a href=\"https:\/\/career.habr.com\/companies\/mts\/vacancies\">\u041c\u0422\u0421 Digital<\/a>. \u042d\u0442\u043e \u0442\u0440\u0435\u0442\u044c\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430 \u043e \u0444\u0438\u0447\u0435 Autoplay \u0444\u0438\u043b\u044c\u043c\u043e\u0432 \u0438 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u043d\u044e\u0430\u043d\u0441\u0430\u0445 \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 tvOS.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/899\/7c1\/bf6\/8997c1bf6fd2c3bbaeed47452cce7fe5.png\" width=\"777\" height=\"438\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/899\/7c1\/bf6\/8997c1bf6fd2c3bbaeed47452cce7fe5.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e Autoplay \u2013 \u044d\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0441\u0430\u043c\u043e\u0439 \u0444\u0438\u0447\u0435 \u0440\u0430\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043c\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u0433\u0430 \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0435\u043b\u044c\u043d\u0438\u043a\u043e\u0432 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/681456\/\"><u>\u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/u><\/a>.<\/p>\n<p><em>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440: \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u0438 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u044f, \u0446\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2013 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u0438\u0442\u044c \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/em><\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e \u0432 \u0441\u0435\u0440\u0438\u0430\u043b\u0430\u0445.<\/p>\n<p>\u0422\u0430\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043b\u043e\u0436\u0438\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0432 KION \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0434\u043b\u044f iOS \u0438 tvOS. \u041f\u0440\u043e\u0435\u043a\u0442\u044b \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u0438 \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0434\u0440\u0443\u0433 \u043a \u0434\u0440\u0443\u0433\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0441\u0432\u043e\u044f, \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 tvOS.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0443, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0442\u0438\u0442\u0440\u044b. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0440\u044f\u0434 \u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0445 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u043d \u0432\u044b\u0439\u0434\u0435\u0442 \u0438\u0437 \u043f\u043b\u0435\u0435\u0440\u0430, \u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.\u00a0<\/p>\n<p>\u041d\u043e \u0436\u0434\u0430\u0442\u044c, \u043f\u043e\u043a\u0430 \u043c\u044b \u0440\u0430\u0437\u043c\u0435\u0442\u0438\u043c \u0432\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u0422\u0430\u043a \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0434\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430. \u0414\u0438\u0437\u0430\u0439\u043d\u0435\u0440\u044b \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043b\u0438 \u0442\u0430\u043a\u0438\u0435 \u043c\u0430\u043a\u0435\u0442\u044b: <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1e5\/5ed\/c24\/1e55edc24e5ea4051f13adcdbb42aa7e.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 1 - \u0410\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 1 - \u0410\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432\" width=\"1600\" height=\"900\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1e5\/5ed\/c24\/1e55edc24e5ea4051f13adcdbb42aa7e.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 1 &#8212; \u0410\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432<\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/571\/ca9\/ecc\/571ca9ecc52d9aa4e6cc059365159491.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 2 - \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 2 - \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b\" width=\"1600\" height=\"900\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/571\/ca9\/ecc\/571ca9ecc52d9aa4e6cc059365159491.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 2 &#8212; \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b<\/figcaption><\/figure>\n<p>\u041a\u043d\u043e\u043f\u043a\u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u043a \u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438. \u041f\u0440\u043e \u0444\u0438\u0447\u0443 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u0440\u0430\u043d\u0435\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u043c\u043e\u0438 \u043a\u043e\u043b\u043b\u0435\u0433\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/661531\/\">\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0435\u043b\u044c\u043d\u0438\u043a\u043e\u0432<\/a> \u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/671922\/\">\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041e\u0445\u0440\u0438\u043c\u0435\u043d\u043a\u043e.<\/a>\u00a0<\/p>\n<p>\u041d\u0430 \u043c\u0430\u043a\u0435\u0442\u0430\u0445 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043a\u043d\u043e\u043f\u043a\u0438 <strong>\u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b<\/strong> \u0438 <strong>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c<\/strong> \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u043c\u0435\u0442\u0440\u0430\u0436\u0435\u043a \u0442\u0430\u043a\u0438\u0435 \u0436\u0435, \u043a\u0430\u043a \u0438 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432. \u0410 \u0437\u043d\u0430\u0447\u0438\u0442, \u044d\u0442\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u0418 \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0430\u0441\u044c, \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u0432 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u2013 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c <strong>PlayerViewController<\/strong> \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0437\u0430 \u0432\u0441\u0435: \u0441\u0430\u043c\u043e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 (\u0441\u0440\u0435\u0434\u0441\u0442\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u043e\u043c), \u043a\u043d\u043e\u043f\u043a\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0435\u0440\u0438\u0438. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043d\u0438\u0436\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ea5\/9f1\/857\/ea59f18575002a5f0cff6a1417145da3.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 3 - \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u043f\u043b\u0435\u0435\u0440\u0435\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 3 - \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u043f\u043b\u0435\u0435\u0440\u0435\" width=\"1465\" height=\"516\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ea5\/9f1\/857\/ea59f18575002a5f0cff6a1417145da3.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 3 &#8212; \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u043f\u043b\u0435\u0435\u0440\u0435<\/figcaption><\/figure>\n<p>\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043f\u043e\u0441\u0442\u0435\u0440 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430 \u043d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d, \u043f\u043e\u0432\u0435\u0440\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u043c\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u0430\u043c \u043f\u043b\u0435\u0435\u0440 \u2013 \u0432 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435, \u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b \u0441\u043a\u0440\u044b\u0442\u044b. \u0412 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0443 \u0442\u0438\u0442\u0440\u043e\u0432 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c.\u00a0<\/p>\n<p>\u0414\u0435\u043b\u0435\u0433\u0430\u0442, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0438\u044f\u043c\u0438 \u2013 <strong>creditsViewDelegate<\/strong> \u2013 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u043e\u0432\u0440\u0435\u043c\u044f \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e. \u041e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0435\u0449\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 \u043f\u043b\u0435\u0435\u0440\u0430, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u0438\u043b\u044c\u043c\u0435 \u0438 \u0443\u043c\u0435\u0442\u044c \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b \u043e\u0442 \u0444\u0438\u043b\u044c\u043c\u0430. \u0412\u0435\u0434\u044c \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u0431\u0435\u0437 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043a\u043e\u0434\u0430 \u044f \u0440\u0435\u0448\u0438\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0437\u043e\u043d\u0430\u043c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438.\u00a0 \u041f\u043e\u0441\u043b\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430, \u0441 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/96f\/c2c\/842\/96fc2c842e15b00ed4267876542428ae.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 4 - \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 4 - \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438\" width=\"1600\" height=\"304\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/96f\/c2c\/842\/96fc2c842e15b00ed4267876542428ae.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 4 &#8212; \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438<\/figcaption><\/figure>\n<p>\u0413\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>PlayerViewControllerProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p><strong>PlayerControlViewControllerProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0430\u043c\u0438 (\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c, \u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0430 \u043f\u0430\u0443\u0437\u0443, \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430);<\/p>\n<\/li>\n<li>\n<p><strong>CreditsViewProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 (\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0438\u044f\u043c\u0438, \u043f\u0440\u043e\u043f\u0443\u0441\u043a \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c).<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043a\u043b\u0430\u0441\u0441 <strong>PlayerViewContainerController<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0438\u043c\u0438 \u0442\u0440\u0435\u043c\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c. \u0410 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0438\u0447\u0438 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0449\u0435.<\/p>\n<p>\u041f\u043e\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u0441\u044f \u0433\u043b\u0443\u0431\u0436\u0435 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438. \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u043a\u0430\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 <strong>MetaChapter<\/strong>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0444\u0438\u0447\u0435-\u0444\u043b\u0430\u0433\u043e\u043c.<\/p>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 (\u043d\u0430\u0447\u0430\u043b\u043e \u0438 \u043a\u043e\u043d\u0435\u0446 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u0438 \u0442\u0438\u0442\u0440\u043e\u0432).<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0e4\/243\/e44\/0e4243e44697151cd6ef936c4ff870d9.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 5 - \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 5 - \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439\" width=\"509\" height=\"170\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0e4\/243\/e44\/0e4243e44697151cd6ef936c4ff870d9.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 5 &#8212; \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439<\/figcaption><\/figure>\n<p>\u0412\u0432\u0435\u0434\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0435\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5b1\/f9b\/fc1\/5b1f9bfc162e1092e74f3fa17a1c7430.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 6 - \u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 6 - \u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"893\" height=\"243\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5b1\/f9b\/fc1\/5b1f9bfc162e1092e74f3fa17a1c7430.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 6 &#8212; \u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f, \u0437\u0430 \u0447\u0442\u043e \u0436\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <strong>CreditsViewController<\/strong> \u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u0430\u043a\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043d\u0438\u043c \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043f\u043e \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0443, \u043d\u0430\u0448\u043b\u0430\u0441\u044c \u043b\u0438 \u0443 \u043d\u0430\u0441 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f (\u041f\u0440\u043e\u043f\u0443\u0441\u043a \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438, \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0435\u0440\u0438\u044f, \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c);<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\/\u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043b\u0435\u0435\u0440\u0430 (\u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c, \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c, \u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c);<\/p>\n<\/li>\n<li>\n<p>\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u043e\u0439, \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0435\u0440 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u0438\u043b\u044c\u043c\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044e \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e UI-\u0441\u043b\u043e\u044f. \u041a\u0430\u043a\u0430\u044f-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438\u0448\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432\u043e\u0432\u043d\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0432\u043e\u0440\u043a\u0435\u0440 ChapterWorker, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c <strong>ChapterWorkingLogic<\/strong>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3cd\/1fd\/c8f\/3cd1fdc8f5b75d65ae1512a93ba65e51.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 7 - \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 7 - \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"691\" height=\"304\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3cd\/1fd\/c8f\/3cd1fdc8f5b75d65ae1512a93ba65e51.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 7 &#8212; \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0439 \u0444\u0438\u0447\u0438:<\/p>\n<pre><code>final class ChapterWorker {     private var chapters: [MetaChapter]? }  extension ChapterWorker: ChapterWorkingLogic {  \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0430\u043f\u0442\u0435\u0440\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441 \u0444\u0438\u043b\u044c\u043c\u0430 \u043d\u0430 \u0444\u0438\u043b\u044c\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u043b\u0435\u0435\u0440\u0435, \u0442\u0430\u043a \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430, \u043c\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043b\u0438\u0448\u044c \u0447\u0430\u043f\u0442\u0435\u0440\u044b     func updateCurrentChapters(chapters: [MetaChapter]?) {         self.chapters = chapters     }  \/\/ \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0432\u0445\u043e\u0434\u0438\u0442 \u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u043e\u0434\u0438\u043d \u0438\u0437 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u043e\u0432     func chapter(currentTime: Double) -> MetaChapter? {         let chapter = chapters?.first(where: {             guard let offTimeString = $0.offTime,                   let endOffsetTimeString = $0.endOffsetTime,                   let offTime = Int(offTimeString),                   let endOffsetTime = Int(endOffsetTimeString),                   offTime &lt; (endOffsetTime - 1) else { return false }             return (offTime..&lt;endOffsetTime) ~= Int(floor(currentTime))         })         return chapter     }  \/\/\u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0442\u0438\u043f\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 (\u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430, \u0442\u0438\u0442\u0440\u044b, \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e)     func chapterType(chapter: MetaChapter?) -> AIVChaptersType {         guard let title = chapter?.title else {             return .none         }         return AIVChaptersType(rawValue: title) ?? .none     } }<\/code><\/pre>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u2013 \u0442\u043e, \u043a\u0430\u043a \u0438 \u043e\u0442\u043a\u0443\u0434\u0430 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0447\u0442\u043e \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 EPlayerView \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0441 \u0442\u0430\u0439\u043c\u0435\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435:<\/p>\n<pre><code>private func addPeriodicTimeObserver() {     if timeObserverToken == nil {         let interval = CMTime(seconds: EPlayerView.periodicTimeInterval, preferredTimescale: CMTimeScale(NSEC_PER_SEC))         timeObserverToken = avPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main) { [weak self] _ in             guard let self = self else {                 return             }             let presentationSize = self.avPlayer?.currentItem?.presentationSize             self.presentationSizeDelegate?.updated(presentationSize: presentationSize)             self.playbackDelegate?.updated(presentationSize: presentationSize)             self.updatePlaybackDataIfNeeded(for: self.type, self.avPlayer?.currentItem)             self.notifyAboutAccessLogEntryIfNeeded(self.avPlayer?.currentItem)         }     } }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0430 \u043e\u043f\u0438\u0441\u0430\u043d \u043d\u0438\u0436\u0435:<\/p>\n<pre><code>private func updatePlaybackDataIfNeeded(for type: EPlayerViewType, _ currentItem: AVPlayerItem?) {     switch type {     case .vod, .trailer:         guard let currentItem = currentItem else {             return         }         delegate?.update(min: 0)         delegate?.update(max: currentItem.duration.seconds)         delegate?.update(current: currentItem.currentTime().seconds)         let currentTimeInSeconds = floor(currentItem.currentTime().seconds)         if floor(chapterTimerCounter) != currentTimeInSeconds {             chapterTimerCounter = currentTimeInSeconds             playbackDelegate?.updateChaptersWithTime(current: currentTimeInSeconds)         }     default:         guard let currentDate = avPlayer?.currentItem?.currentDate() else {             return         }         if let s = startDate {             self.delegate?.update(start: s)         }         if let e = endDate {             self.delegate?.update(end: e)         }         delegate?.update(current: currentDate)         NotificationCenter.default.post(name: .livePlayerDidUpdateTimeNotification,                                         object: nil,                                         userInfo: [EPlayerView.keyFTS: currentDate.timeIntervalSince1970])     }     playbackDelegate?.playerPlaybackStateDidChange(to: playbackState) }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0433\u0434\u0435 <strong>chapterTimerCounter<\/strong> \u2013 \u0441\u0447\u0435\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u043e\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u0442\u0440\u043e\u0432, \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u044b\u0448\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 ChapterWorker.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0414\u0430\u043b\u0435\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441 \u0441\u0430\u043c\u0438\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u043c \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/109\/2db\/56d\/1092db56d13dbffe728ed6664741a613.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 8 - \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 8 - \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"650\" height=\"362\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/109\/2db\/56d\/1092db56d13dbffe728ed6664741a613.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 8 &#8212; \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0413\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>buttonsView<\/strong> \u2013 \u043a\u043d\u043e\u043f\u043a\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0444\u043e\u043a\u0443\u0441\u0430 \u043c\u0435\u0436\u0434\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043a\u043d\u043e\u043f\u043e\u043a \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 UIFocusGuide;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>updateAutoplayData(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>checkCurrentTimeChapter(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0443\u0447\u0430\u0441\u0442\u043e\u043a \u043f\u0440\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0430\u0445 (\u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u2013 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430);\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>setCreditsForEndPlayingState()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435 \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u044d\u043a\u0440\u0430\u043d \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f, \u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u043d\u0435\u0442 \u0438\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b \u0438 \u0434\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432\u0441\u0435 \u0434\u043e \u043a\u043e\u043d\u0446\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>updateVisibility()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043d\u043e\u043f\u043e\u043a \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>controlsVisibilityWasChanged(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 \u0431\u044b\u043b\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430 (\u0441\u043f\u0440\u044f\u0442\u0430\u043d\u044b \u0438\u043b\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b);\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>menuButtonWasTapped()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \u041c\u0435\u043d\u044e \u043d\u0430 \u043f\u0443\u043b\u044c\u0442\u0435;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>bringToFront()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 view \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439 \u0441\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u043a\u0430\u043a \u0436\u0435 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044e \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c? \u0412\u0435\u0434\u044c \u0435\u043c\u0443 \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 (\u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0442\u044c \u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c), \u0430 \u0435\u0449\u0435 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0435\u0440\u0435\u043c\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f, \u043f\u0440\u044f\u0442\u0430\u0442\u044c \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0434\u0435\u043b\u0435\u0433\u0430\u0442 <strong>CreditsViewDelegate<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d2c\/5f9\/08e\/d2c5f908eb41d047f7eae67e3002159a.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 9 - \u0414\u0435\u043b\u0435\u0433\u0430\u0442 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 9 - \u0414\u0435\u043b\u0435\u0433\u0430\u0442 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\" width=\"1278\" height=\"427\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d2c\/5f9\/08e\/d2c5f908eb41d047f7eae67e3002159a.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 9 &#8212; \u0414\u0435\u043b\u0435\u0433\u0430\u0442 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440<\/figcaption><\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0443\u0436\u043d\u044b \u044d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430:<\/p>\n<ul>\n<li>\n<p><strong>constantsForPlayerAndDescriptionPosition<\/strong> \u2013 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0430\u044f \u0437\u0430 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430 (\u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c, \u0447\u0442\u043e\u0431 \u0431\u044b\u043b\u043e \u0432 \u043e\u0434\u043d\u0443 \u043b\u0438\u043d\u0438\u044e \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c);<\/p>\n<\/li>\n<li>\n<p><strong>skipIntroTo(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0432 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438;<\/p>\n<\/li>\n<li>\n<p><strong>nextButtonWasPressed(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 (\u0444\u0438\u043b\u044c\u043c, \u0441\u0435\u0440\u0438\u044f \u0438 \u0442.\u043f.), \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 (\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c) \u0438\u043b\u0438 \u043d\u0435\u0442 (\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0430\u043b \u0441\u0430\u043c);<\/p>\n<\/li>\n<li>\n<p><strong>updatePlayerState(&#8230;)<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430 (\u0441\u0432\u0435\u0440\u043d\u0443\u0442\u044c, \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c, \u0441\u043a\u0440\u044b\u0442\u044c, \u0437\u0430\u043a\u0440\u044b\u0442\u044c);<\/p>\n<\/li>\n<li>\n<p><strong>bringViewToFrontAndUpdateFocusIfNeeded()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u043e\u043a\u0443\u0441\u0430;<\/p>\n<\/li>\n<li>\n<p><strong>showControls()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p><strong>hideControls()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p><strong>hideTabBar()<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0430\u0431\u0431\u0430\u0440\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 (\u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430 \u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0435\u043c \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u043d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d).<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043f\u043b\u0435\u0435\u0440\u0443 \u0438 \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f?<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c7a\/8be\/e90\/c7a8bee90fa381e21b16c1a6e82481d8.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 10 - \u041f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 10 - \u041f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430\" width=\"1009\" height=\"178\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c7a\/8be\/e90\/c7a8bee90fa381e21b16c1a6e82481d8.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 10 &#8212; \u041f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430<\/figcaption><\/figure>\n<p>\u0412 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430\u0448\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <strong>AutoLayout<\/strong>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0441\u0435 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0440\u0430\u0437\u043c\u0435\u0440\u0430\u043c\u0438 \u044f \u043f\u0440\u043e\u0432\u043e\u0436\u0443 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442 \u0443 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e \u0434\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u044e \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u043b\u0435\u0435\u0440\u0430. \u041d\u0438\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e, \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<pre><code>private func updatePlayerDisplaying(state: VODPlayerState) {     guard self.state != state else {         return     }     self.state = state     switch state {     case .normal:         playerView?.isHidden = false         playerView?.cornersRadius = playerDefaultCornerRadius resetPlayerConstantsToZero()     case .minimized:         playerView?.isHidden = false         playerView?.cornersRadius = playerMinimizedCornerRadius         if let position = containerDelegate?.constantsForPlayerAndDescriptionPosition { updatePlayerConstants(to: position)         }     case .hidden:         playerView?.isHidden = true         playerView?.cornersRadius = playerDefaultCornerRadius     case .closed:         closePlayer()     }     UIView.animate(withDuration: 0.5) {         self.view.layoutIfNeeded()     } }<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u043e\u0434\u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433, \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u0438 \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0443\u044e\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438 \u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/40b\/c97\/f48\/40bc97f4819be0915d79e2a83c887104.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 11 - \u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 11 - \u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"1600\" height=\"527\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/40b\/c97\/f48\/40bc97f4819be0915d79e2a83c887104.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 11 &#8212; \u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0422\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u2013 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u043c\u0435\u0436\u0434\u0443 \u043f\u043b\u0435\u0435\u0440\u043e\u043c, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0430\u043c\u0438 \u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0435\u043c:<\/p>\n<pre><code>final class VodPlayerViewContainerController: BaseViewController {     private var playerViewControllerProtocol: VodPlayerViewControllerProtocol?     private var controlsViewControllerProtocol: EPlayerControlViewControllerProtocol?     private var creditsViewControllerProtocol: CreditsViewProtocol?      private var isFirstCheck: Bool = true     private var isPlayerDataReloaded: Bool = false      private var bottomControlsLayoutConstraint: NSLayoutConstraint?     private let bottomControlsInsetByDefault: CGFloat = 0      public typealias PlayerAndDescriptionPosition = (bottom: CGFloat, leading: CGFloat, top: CGFloat, trailing: CGFloat)      public lazy var constantsForPlayerAndDescriptionPosition: PlayerAndDescriptionPosition = {         let height = view.frame.size.height         let width = view.frame.size.width          let quarter: CGFloat = 0.25         let minHeight = quarter * height         let minWidth = quarter * width          let bottom: CGFloat = 130         let leading = bottom         let top = height - bottom - minHeight         let trailing = width - leading - minWidth          return (bottom, leading, top, trailing)     }()      override var preferredFocusEnvironments: [UIFocusEnvironment] {         if let controlsView = controlsViewControllerProtocol?.controlsViewController.view,             controlsViewControllerProtocol?.isControlsShown == true {             return [controlsView]         }         if let buttonsView = creditsViewProtocol?.buttonsView {             return [buttonsView]         }         return super.preferredFocusEnvironments     }      \/\/ MARK: - Life Cycle      init(type: VodPlayerType, recommendationsDelegate: MovieRecommendationsDelegate?, viewWillDimissClosureAtTime: DoubleClosure?) {         super.init(nibName: nil, bundle: nil)         configurePlayerViewController(type: type, recommendationsDelegate: recommendationsDelegate, viewWillDimissClosureAtTime: viewWillDimissClosureAtTime)         configureCreditsView()         addGesturesToView()     }      required init?(coder: NSCoder) {         fatalError(\"init(coder:) has not been implemented\")     }      \/\/ MARK: - Overrides      override func pressesBegan(_ presses: Set&lt;UIPress>, with event: UIPressesEvent?) {         for press in presses {             switch press.type {             case .playPause:                 playerViewControllerProtocol?.playerViewController.pressesBegan(presses, with: event)             default:                 super.pressesBegan(presses, with: event)             }         }     }      \/\/ MARK: - Actions      @objc func menuButtonAction() {         if controlsViewControllerProtocol?.isControlsShown == true {             controlsViewControllerProtocol?.hideControls()         } else {             creditsViewControllerProtocol?.menuButtonWasTapped()         }     }      \/\/ MARK: - Privates      private func configurePlayerViewController(type: VodPlayerType, recommendationsDelegate: MovieRecommendationsDelegate?, viewWillDimissClosureAtTime: DoubleClosure?) {         playerViewControllerProtocol = VodPlayerViewController.instance(type: type,                                                                         recommendationsDelegate: recommendationsDelegate,                                                                         viewWillDimissClosureAtTime: viewWillDimissClosureAtTime)          playerViewControllerProtocol?.setContainerDelegate(delegate: self)         if let childController = playerViewControllerProtocol?.playerViewController {             add(child: childController)         }     }      private func configureCreditsView() {         let creditsViewController = CreditsBuilder().makeCreditsModule(delegate: self)         creditsViewControllerProtocol.translatesAutoresizingMaskIntoConstraints = false         view.add(child: creditsViewController)          creditsViewControllerProtocol = creditsViewController     }      private func configureControlsViewControllerIfNeeded() {         guard controlsViewControllerProtocol == nil,               let player = playerViewControllerProtocol?.playerView,               let titleModel = playerViewControllerProtocol?.titleViewModel else {                   bottomControlsLayoutConstraint?.constant = bottomControlsInsetByDefault             return         }         controlsViewControllerProtocol = EPlayerControlViewController.instance(view: player, titleModel: titleModel)          controlsViewControllerProtocol?.showContentRating = { [weak self] contentRatingImage in             self?.playerViewControllerProtocol?.configureContentRating(image: contentRatingImage)         }         controlsViewControllerProtocol?.setupPlayerControlsDelegate(delegate: self)         player.delegate = controlsViewControllerProtocol?.controlsViewController          if let childController = controlsViewControllerProtocol?.controlsViewController {             childController.view.translatesAutoresizingMaskIntoConstraints = false             addChild(childController)             view.addSubview(childController.view)             childController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true             childController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true             childController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true             bottomControlsLayoutConstraint = childController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: bottomControlsInsetByDefault)             bottomControlsLayoutConstraint?.isActive = true             childController.didMove(toParent: self)         }          if let controlsViewControllerProtocol = controlsViewControllerProtocol,            let creditsViewProtocol = creditsViewProtocol {             view.addFocusGuide(from: controlsViewControllerProtocol.controlsViewController.view, to: creditsViewProtocol.buttonsView, direction: .top)             view.addFocusGuide(from: creditsViewProtocol.buttonsView, to: controlsViewControllerProtocol.controlsViewController.view, direction: .bottom)         }     }      private func removeControlsViewController() {         if let childController = controlsViewControllerProtocol?.controlsViewController {             remove(child: childController)             controlsViewControllerProtocol = nil         }     }      private func addGesturesToView() {         view.addTapGesture { [weak self] in             self?.playerViewControllerProtocol?.viewDidTap()             if self?.playerViewControllerProtocol?.isControlsShouldBeShown == true {                 self?.showControls()             }         }          let menuRecognizer = view.addMenuButtonTap { [weak self] in             self?.menuButtonAction()         }         menuRecognizer.cancelsTouchesInView = true     }      func updateEPlayerData() {         guard let titleModel = playerViewControllerProtocol?.titleViewModel else {             return         }         controlsViewControllerProtocol?.updateTitle(with: titleModel)     } }  \/\/ MARK: - VodPlayerViewContainerControllerProtocol extension VodPlayerViewContainerController: VodPlayerViewContainerControllerProtocol {     func updateAndConfigureWith(type: VodPlayerType) {         playerViewControllerProtocol?.updateAndConfigureWith(type: type)     } }  \/\/ MARK: - VodContainerDelegate extension VodPlayerViewContainerController: VodContainerDelegate {     func updateAutoplayData(chapters: [MetaChapter]?, contentModel: VodPlayerViewModel) {         creditsViewControllerProtocol?.updateAutoplayData(chapters: chapters, contentModel: contentModel)     }      func checkCurrentTimeChapter(time: Double) {         creditsViewControllerProtocol?.checkCurrentTimeChapter(time: time, isControlsShown: controlsViewControllerProtocol?.isControlsShown ?? false, isFirstCheck: isFirstCheck)         isFirstCheck = false     }      func handleEndMoviePlaying() {         creditsViewControllerProtocol?.setCreditsForEndPlayingState()         removeControlsViewController()     }      func onboardingIsShown(isShown: Bool) {         creditsViewControllerProtocol?.updateVisibility(isHidden: isShown)     }      func close() {         dismiss(animated: true)     }      func dismissControls() {         removeControlsViewController()     }      func playingContentDataDidUpdate() {         isPlayerDataReloaded = true         updateEPlayerData()     } }  \/\/ MARK: - PlayerControlsProtocol extension VodPlayerViewContainerController: PlayerControlsProtocol {     func sliderInProgress(isInProgress: Bool) {         creditsViewControllerProtocol?.updateVisibility(isHidden: isInProgress)     }      func controlsWasShown() {         creditsViewControllerProtocol?.controlsVisibilityWasChanged(isControlsHidden: false)         creditsViewControllerProtocol?.bringToFront()     }      func controlsWasHidden() {         creditsViewControllerProtocol?.controlsVisibilityWasChanged(isControlsHidden: true)         similarInPlayerViewProtocol?.hideSimilarShelfIfNeeded()     } }  \/\/ MARK: - CreditsViewDelegate extension VodPlayerViewContainerController: CreditsViewDelegate {     func skipIntroTo(time: Double) {         MovieStoriesManager.shared.currentChapterInFilmPlayMode?.wasActivated = true         playerViewControllerProtocol?.playerView?.rewind(time)     }      func nextButtonWasPressed(isAuto: Bool) {         MovieStoriesManager.shared.currentTime = 0         playerViewControllerProtocol?.playerViewModel.playNext(isAuto: isAuto)     }      func updatePlayerState(state: VODPlayerState) {         playerViewControllerProtocol?.updatePlayerDisplaying(state: state)     }      func bringViewToFrontAndUpdateFocusIfNeeded() {         creditsViewControllerProtocol?.bringToFront()         setNeedsFocusUpdate()         updateFocusIfNeeded()     }      func showControls() {         configureControlsViewControllerIfNeeded()         configureSimilarInPlayerViewIfNeeded()         controlsViewControllerProtocol?.showControlsIfNeeded()         creditsViewControllerProtocol?.controlsVisibilityWasChanged(isControlsHidden: false)         isPlayerDataReloaded = false         setNeedsFocusUpdate()         updateFocusIfNeeded()     }      func hideControls() {         dismissControls()     }      func hideTabBar() {         if let tabBarController = presentedViewController as? ExpandableTabBarController {             tabBarController.dismiss()         }     } }<\/code><\/pre>\n<p>\u041d\u043e\u0432\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043d\u043e\u0432\u043e\u0439 \u0436\u0435 <strong>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b VIP<\/strong>. \u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0432\u0441\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u043d\u0430 \u044d\u0442\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u0430 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u043d\u0435\u0439 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u043d\u0430\u0448\u0435\u0439 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u0410 \u043f\u043e\u043a\u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043a\u0440\u0430\u0442\u043a\u043e.<\/p>\n<p>\u0412 VIP-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u0441\u0446\u0435\u043d, \u0438 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0446\u0435\u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0446\u0438\u043a\u043b\u0443 VIP. \u0421\u0446\u0435\u043d\u0430 \u0437\u0434\u0435\u0441\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435. \u041d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0441\u0446\u0435\u043d\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d, \u2013 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u043c\u0435\u0442\u044c \u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/597\/889\/94b\/59788994bc8c6b2044b2fa86c418d632.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 12 -  \u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b VIP-\u0446\u0438\u043a\u043b\u0430\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 12 -  \u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b VIP-\u0446\u0438\u043a\u043b\u0430\" width=\"880\" height=\"660\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/597\/889\/94b\/59788994bc8c6b2044b2fa86c418d632.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 12 &#8212;  \u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b VIP-\u0446\u0438\u043a\u043b\u0430<\/figcaption><\/figure>\n<p>\u041f\u043e\u0442\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 VIP Architecture \u2013 \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439. <strong>ViewController<\/strong> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0438\u0445 \u0432 Interactor \u0432 \u0432\u0438\u0434\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0417\u0430\u0442\u0435\u043c <strong>Interactor<\/strong> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 API) \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 <strong>Presenter<\/strong> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0442\u0432\u0435\u0442\u0430. Presenter \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u043e \u0435\u0441\u0442\u044c \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430, \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b) \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 ViewController.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u0439 \u0441\u0446\u0435\u043d\u0435 \u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0435\u043c \u0438 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430. \u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043d\u0430 \u0441\u0445\u0435\u043c\u0435:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ab7\/98d\/bd2\/ab798dbd2f53bacd87216fdf1b1ce15d.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 13 -  VIP-\u0446\u0438\u043a\u043b \u0441\u0446\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 13 -  VIP-\u0446\u0438\u043a\u043b \u0441\u0446\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"1600\" height=\"643\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ab7\/98d\/bd2\/ab798dbd2f53bacd87216fdf1b1ce15d.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 13 &#8212;  VIP-\u0446\u0438\u043a\u043b \u0441\u0446\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0410 \u043d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<pre><code>final class CreditsViewController: UIViewController {     weak var delegate: CreditsViewDelegate?     var interactor: CreditsBusinessLogic?      private var isCreditsHidden: Bool = true     private var isControlsHidden: Bool = true     private var headCreditsHideTimer: Timer?     private var topDescriptionStackConstraint: NSLayoutConstraint?     private var bottomDescriptionStackConstraint: NSLayoutConstraint?      private var posterBackgroundImageView: UIImageView = {         let imageView = UIImageView()         imageView.translatesAutoresizingMaskIntoConstraints = false         imageView.contentMode = .scaleAspectFit         imageView.isHidden = true         return imageView     }()      private let gradientSublayer: CAGradientLayer = {         let layer = CAGradientLayer()         layer.colors = [             UIColor.clear.cgColor,             UIColor.black.cgColor         ]         layer.locations = [0, 0.98]         return layer     }()      private lazy var descriptionStack: NextSimilarContentDescriptionStack = {         let stack = NextSimilarContentDescriptionStack()         stack.translatesAutoresizingMaskIntoConstraints = false         return stack     }()      lazy var buttonsView: CreditsButtonsView = {         let view: CreditsButtonsView = .instanceFromNib()!         view.translatesAutoresizingMaskIntoConstraints = false         view.delegate = self         return view     }()      override var preferredFocusEnvironments: [UIFocusEnvironment] {         [buttonsView]     }      \/\/ MARK: - Life Cycle      deinit {         dropHeadCreditsHideTimer()     }      \/\/ MARK: - Overrides      override func viewDidLayoutSubviews() {         super.viewDidLayoutSubviews()         interactor?.updateGradientFrame(request: CreditsModels.GradientFrameUpdates.Request(frame: posterBackgroundImageView.frame))     }      \/\/ MARK: - Privates      private func setupViewsIfNeeded() {         guard posterBackgroundImageView.superview == nil else {             return         }         \/\/ \u043f\u043e\u0441\u0442\u0435\u0440 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0441\u0442\u0435\u043a, \u0447\u0442\u043e\u0431 \u043d\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435\u043c \u0444\u043e\u043a\u0443\u0441\u0430 \u043a\u043d\u043e\u043f\u043e\u043a, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u0441\u0442\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0437\u0430\u0434\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043f\u043b\u0435\u0435\u0440\u0430         view.superview?.addSubview(posterBackgroundImageView)         posterBackgroundImageView.bindToSuperviewBounds()         posterBackgroundImageView.layer.addSublayer(gradientSublayer)         view.addSubview(buttonsView)         buttonsView.bindToSuperviewBounds()         if let position = delegate?.constantsForPlayerAndDescriptionPosition {             setupDescriptionStackConstraints(position: position)         }     }      private func setupDescriptionStackConstraints(position: VodPlayerViewContainerController.PlayerAndDescriptionPosition) {         view.addSubview(descriptionStack)         topDescriptionStackConstraint = descriptionStack.topAnchor.constraint(equalTo: view.topAnchor, constant: position.top)         topDescriptionStackConstraint?.isActive = true         bottomDescriptionStackConstraint = descriptionStack.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -position.bottom - 100)         bottomDescriptionStackConstraint?.isActive = false         descriptionStack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -90).isActive = true         descriptionStack.leadingAnchor.constraint(equalTo: view.trailingAnchor, constant: -position.trailing + 25).isActive = true     }      private func updateDescriptionStackPosition(onlyTitle: Bool) {         topDescriptionStackConstraint?.isActive = !onlyTitle         bottomDescriptionStackConstraint?.isActive = onlyTitle         view.layoutIfNeeded()     }      private func updateCreditsView(creditsType: AIVCreditsType?,                                    nextButtonTitle: AIVCreditsNextButtonTitle?,                                    toTime: Double?,                                    animationDuration: Int,                                    state: NextSimilarContentDescriptionStack.NextSimilarContentDescriptionState,                                    isBackgroundPosterHidden: Bool,                                    playerState: VODPlayerState) {         posterBackgroundImageView.isHidden = isBackgroundPosterHidden         view.superview?.sendSubviewToBack(posterBackgroundImageView)          descriptionStack.configure(state: state)         updateDescriptionStackPosition(onlyTitle: state == .shownOnlyTitle)          delegate?.updatePlayerState(state: playerState)          updateButtonsView(creditsType: creditsType,                           nextButtonTitle: nextButtonTitle,                           toTime: toTime,                           animationDuration: animationDuration)          \u0441reditsTypeDidUpdate(creditsType: creditsType)          view.isHidden = isCreditsHidden     }      private func updateButtonsView(creditsType: AIVCreditsType?,                                    nextButtonTitle: AIVCreditsNextButtonTitle?,                                    toTime: Double?,                                    animationDuration: Int) {         buttonsView.configure(nextButtonTitle: nextButtonTitle)         buttonsView.configure(state: creditsType,                               endTime: toTime,                               animationDuration: animationDuration)         view.bringSubviewToFront(buttonsView)     }      private func \u0441reditsTypeDidUpdate(creditsType: AIVCreditsType?) {         switch creditsType {         case .head where isControlsHidden:             delegate?.bringViewToFrontAndUpdateFocusIfNeeded()             updateFocus()         case .tail, .tailOnlyNextWithAnimation:             delegate?.hideTabBar()             delegate?.bringViewToFrontAndUpdateFocusIfNeeded()             updateFocus()         case .some(.head), .tailOnlyNextWithoutAnimation, .playNext, .none:             break         }     }      private func updateFocus() {         setNeedsFocusUpdate()         updateFocusIfNeeded()     }      private func forceChangeVisibility(isHidden: Bool) {         isCreditsHidden = isHidden         view.isHidden = isCreditsHidden     }      private func dropHeadCreditsHideTimer() {         interactor?.updateTimer(request: CreditsModels.UpdateTimer.Request(shouldTimerStart: false))     } }  \/\/ MARK: - CreditsDisplayLogic  extension CreditsView: CreditsDisplayLogic {     func updateData(viewModel: CreditsModels.UpdateAutoplayData.ViewModel) {         setupViewsIfNeeded()         descriptionStack.configureDescription(info: viewModel.info)         posterBackgroundImageView.loadImage(path: viewModel.path, size: bounds.size)     }      func moveView(viewModel: CreditsModels.MoveView.ViewModel) {         UIView.animate(withDuration: 0.5) {             self.view.transform = viewModel.transform         }     }      func updateGradientFrame(viewModel: CreditsModels.GradientFrameUpdates.ViewModel) {         gradientSublayer.frame = viewModel.frame     }      func bringSubviewToFront(viewModel: CreditsModels.LayoutUpdates.ViewModel) {         view.superview?.bringSubviewToFront(self)     }      func updateCreditsView(viewModel: CreditsModels.SearchCurrentChapter.ViewModel) {         isCreditsHidden = viewModel.isHidden         if viewModel.shouldShowControls {             delegate?.showControls()         }         updateCreditsView(creditsType: viewModel.creditsType,                           nextButtonTitle: viewModel.nextButtonTitle,                           toTime: viewModel.toTime,                           animationDuration: viewModel.animationDuration,                           state: viewModel.state,                           isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                           playerState: viewModel.playerState)     }      func updateCreditsView(viewModel: CreditsModels.UpdateCreditsType.ViewModel) {         isCreditsHidden = viewModel.isHidden         updateCreditsView(creditsType: viewModel.creditsType,                           nextButtonTitle: viewModel.nextButtonTitle,                           toTime: viewModel.toTime,                           animationDuration: viewModel.animationDuration,                           state: viewModel.state,                           isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                           playerState: viewModel.playerState)     }      func updateVisibility(viewModel: CreditsModels.UpdateVisibility.ViewModel) {         isCreditsHidden = viewModel.isHidden         updateCreditsView(creditsType: viewModel.creditsType,                           nextButtonTitle: viewModel.nextButtonTitle,                           toTime: viewModel.toTime,                           animationDuration: viewModel.animationDuration,                           state: viewModel.state,                           isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                           playerState: viewModel.playerState)     }      func controlsVisibilityChanged(viewModel: CreditsModels.ControlsVisibilityWasChanged.ViewModel) {         isControlsHidden = viewModel.isControlsHidden         forceChangeVisibility(isHidden: viewModel.isHidden)     }      func showCredits(viewModel: CreditsModels.UpdateCreditsType.ViewModel) {         isCreditsHidden = viewModel.isHidden         updateCreditsView(creditsType: viewModel.creditsType,                           nextButtonTitle: viewModel.nextButtonTitle,                           toTime: viewModel.toTime,                           animationDuration: viewModel.animationDuration,                           state: viewModel.state,                           isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                           playerState: viewModel.playerState)         delegate?.hideControls()     }      func playNext(viewModel: CreditsModels.NextButtonDidPress.ViewModel) {         isCreditsHidden = viewModel.isHidden         updateCreditsView(creditsType: viewModel.creditsType,                           nextButtonTitle: viewModel.nextButtonTitle,                           toTime: viewModel.toTime,                           animationDuration: viewModel.animationDuration,                           state: viewModel.state,                           isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                           playerState: viewModel.playerState)         delegate?.nextButtonWasPressed(isAuto: viewModel.isAuto)     }      func skipIntro(viewModel: CreditsModels.SkipIntro.ViewModel) {         dropHeadCreditsHideTimer()         delegate?.skipIntroTo(time: viewModel.time)         delegate?.hideControls()     }      func startTimer(viewModel: CreditsModels.UpdateTimer.ViewModel) {         headCreditsHideTimer?.invalidate()         headCreditsHideTimer = Timer.scheduledTimer(timeInterval: viewModel.skipIntroTimeInterval,                                                     target: self,                                                     selector: #selector(skipTimerAction),                                                     userInfo: nil,                                                     repeats: true)         forceChangeVisibility(isHidden: viewModel.isHidden)     }      func dropTimer(viewModel: CreditsModels.UpdateTimer.ViewModel) {         headCreditsHideTimer?.invalidate()         headCreditsHideTimer = nil         forceChangeVisibility(isHidden: viewModel.isHidden)     }      func menuButtonWasTapped(viewModel: CreditsModels.MenuButtonTapped.ViewModel) {         interactor?.sendMenuButtonAnalytics(request: CreditsModels.AnalyticsData.Request(buttonType: viewModel.buttonType, isAutomatically: viewModel.isAutomatically))          if viewModel.creditsType != nil {             skipTimerAction()         } else {             updateCreditsView(creditsType: viewModel.creditsType,                               nextButtonTitle: viewModel.nextButtonTitle,                               toTime: viewModel.toTime,                               animationDuration: viewModel.animationDuration,                               state: viewModel.state,                               isBackgroundPosterHidden: viewModel.isBackgroundPosterHidden,                               playerState: viewModel.playerState)         }     }      func sendButtonsAnalytics(viewModel: CreditsModels.AnalyticsData.ViewModel) {         \/\/ \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0446\u0438\u043a\u043b\u0430 (\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430)     } }  \/\/ MARK: - CreditsDelegate  extension CreditsView: CreditsViewProtocol {     func updateAutoplayData(chapters: [MetaChapter]?, contentModel: VodPlayerViewModel) {         let request = CreditsModels.UpdateAutoplayData.Request(chapters: chapters,                                                                  contentModel: contentModel)         interactor?.updateData(request: request)     }      func checkCurrentTimeChapter(time: Double, isControlsShown: Bool, isFirstCheck: Bool) {         let request = CreditsModels.SearchCurrentChapter.Request(currentTime: time,                                                                  isControlsShown: isControlsShown,                                                                  isFirstCheck: isFirstCheck)         interactor?.findCurrentChapter(request: request)     }      func setCreditsForEndPlayingState() {         interactor?.didContentEnd(request: CreditsModels.UpdateCreditsType.Request())     }      func updateVisibility(isHidden: Bool) {         let request = CreditsModels.UpdateVisibility.Request(shouldBeHidden: isHidden)         interactor?.visibilityShouldBeChanged(request: request)     }      func controlsVisibilityWasChanged(isControlsHidden: Bool) {         let request = CreditsModels.ControlsVisibilityWasChanged.Request(isControlsHidden: isControlsHidden)         interactor?.controlsVisibilityChanged(request: request)     }      func menuButtonWasTapped() {         interactor?.menuButtonWasTapped(request: CreditsModels.MenuButtonTapped.Request())     }      func moveCreditsView(inset: CGFloat) {         let request = CreditsModels.MoveView.Request(inset: inset)         interactor?.moveView(request: request)     }      func bringToFront() {         interactor?.bringSubviewToFront(request: CreditsModels.LayoutUpdates.Request())     } }  \/\/ MARK: - CreditsButtonsViewDelegate  extension CreditsView: CreditsButtonsViewDelegate {     func skipIntroTo(time: Double) {         interactor?.skipIntro(request: CreditsModels.SkipIntro.Request(time: time))     }      func showCredits() {         interactor?.showCredits(request: CreditsModels.UpdateCreditsType.Request())     }      func playNext(isAuto: Bool) {         interactor?.playNext(request: CreditsModels.NextButtonDidPress.Request(isAuto: isAuto))     }      func startSkipIntroTimerIfNeeded() {         interactor?.updateTimer(request: CreditsModels.UpdateTimer.Request(shouldTimerStart: true))     }      @objc func skipTimerAction() {         dropHeadCreditsHideTimer()     }      func sendButtonShowsAnalytics(buttonType: AIVAnalyticsKeys.ButtonTypes?) {         let request = CreditsModels.AnalyticsData.Request(buttonType: buttonType, isAutomatically: nil)         interactor?.sendButtonShowsAnalytics(request: request)     }      func sendButtonWasTappedAnalytics(buttonType: AIVAnalyticsKeys.ButtonTypes?, isAutomatically: Bool) {         let request = CreditsModels.AnalyticsData.Request(buttonType: buttonType, isAutomatically: isAutomatically)         interactor?.sendButtonWasTappedAnalytics(request: request)     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432 <strong>Interactor<\/strong>, \u0437\u0434\u0435\u0441\u044c \u0443 \u043d\u0430\u0441 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u043e\u0442\u0441\u044b\u043b\u043a\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 \u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 <strong>Worker<\/strong> \u043f\u043e\u0438\u0441\u043a\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438:<\/p>\n<pre><code>final class CreditsInteractor {     var presenter: CreditsPresentationLogic?     private var chapterWorker: ChapterWorkingLogic?     private var remoteConfigWorker: AIVRemoteConfigWorkerLogic?     private var analyticsEventForCurrent: Analytics.PlaybackButtonsEvent?     private var analyticsEventForRecommended: Analytics.PlaybackButtonsEvent?     private (set) var animationDuration: Int = 0      init(with chapterWorker: ChapterWorkingLogic, remoteConfigWorker: AIVRemoteConfigWorkerLogic) {         self.chapterWorker = chapterWorker         self.remoteConfigWorker = remoteConfigWorker     }      func creditsContentType(contentModel: VodPlayerViewModel) -> ContentType {         switch contentModel.type {         case .vod:             return .movie         case .serial:             return .serial(serialInfo: VideoDetailViewModel.SerialInfo())         case .trailer, .none:             return .none         }     } }  \/\/ MARK: - CreditsBusinessLogic extension CreditsInteractor: CreditsBusinessLogic {     func updateGradientFrame(request: CreditsModels.GradientFrameUpdates.Request) {         presenter?.updateGradientFrame(response: CreditsModels.GradientFrameUpdates.Response(frame: request.frame))     }      func moveView(request: CreditsModels.MoveView.Request) {         presenter?.moveView(response: CreditsModels.MoveView.Response(inset: request.inset))     }      func bringSubviewToFront(request: CreditsModels.LayoutUpdates.Request) {         presenter?.bringSubviewToFront(response: CreditsModels.LayoutUpdates.Response())     }      func updateData(request: CreditsModels.UpdateAutoplayData.Request) {         guard let remoteConfigWorker = remoteConfigWorker else {             return         }         analyticsEventForCurrent = request.contentModel.analyticsEventForCurrentContent         analyticsEventForRecommended = request.contentModel.analyticsEventForRecommendedContent         chapterWorker?.updateCurrentChapters(chapters: request.chapters)          let currentContentType = creditsContentType(contentModel: request.contentModel)         animationDuration = remoteConfigWorker.durationForAnimation(currentContentType: currentContentType)          let delegate = request.contentModel.recommendationsDelegate         let isMoviesAutoplayShouldBeShown = remoteConfigWorker.isMoviesAutoplayFunctionalityEnabled &amp;&amp; delegate?.firstRecommendedVod != nil          let currentContentTypeResponse = CreditsModels.UpdateAutoplayData.Response(currentContentType: currentContentType,                                                                                      isMoviesAutoplayShouldBeShown: isMoviesAutoplayShouldBeShown,                                                                                      info: delegate?.viewModelForDescripton(),                                                                                      path: delegate?.pathForPoster())         presenter?.updateData(response: currentContentTypeResponse)     }      func findCurrentChapter(request: CreditsModels.SearchCurrentChapter.Request) {         guard let chapterWorker = chapterWorker else {             return         }         let chapter = chapterWorker.chapter(currentTime: request.currentTime)         let response = CreditsModels.SearchCurrentChapter.Response(chapter: chapter,                                                                    isControlsShown: request.isControlsShown,                                                                    isFirstCheck: request.isFirstCheck,                                                                    chapterType: chapterWorker.chapterType(chapter: chapter),                                                                    animationDuration: animationDuration)         presenter?.didFindChapter(response: response)     }      func skipIntro(request: CreditsModels.SkipIntro.Request) {         presenter?.skipIntro(response: CreditsModels.SkipIntro.Response(time: request.time))     }      func didContentEnd(request: CreditsModels.UpdateCreditsType.Request) {         let response = CreditsModels.UpdateCreditsType.Response(animationDuration: animationDuration)         presenter?.didContentEnd(response: response)     }      func showCredits(request: CreditsModels.UpdateCreditsType.Request) {         let response = CreditsModels.UpdateCreditsType.Response(animationDuration: animationDuration)         presenter?.showCredits(response: response)     }      func playNext(request: CreditsModels.NextButtonDidPress.Request) {         let response = CreditsModels.NextButtonDidPress.Response(isAuto: request.isAuto,                                                                  animationDuration: animationDuration)         presenter?.playNext(response: response)     }      func visibilityShouldBeChanged(request: CreditsModels.UpdateVisibility.Request) {         let response = CreditsModels.UpdateVisibility.Response(shouldBeHidden: request.shouldBeHidden,                                                                animationDuration: animationDuration)         presenter?.visibilityShouldBeChanged(response: response)     }      func controlsVisibilityChanged(request: CreditsModels.ControlsVisibilityWasChanged.Request) {         let response = CreditsModels.ControlsVisibilityWasChanged.Response(isControlsHidden: request.isControlsHidden)         presenter?.controlsVisibilityChanged(response: response)     }      func updateTimer(request: CreditsModels.UpdateTimer.Request) {         presenter?.updateTimer(response: CreditsModels.UpdateTimer.Response(shouldTimerStart: request.shouldTimerStart))     }      func menuButtonWasTapped(request: CreditsModels.MenuButtonTapped.Request) {         presenter?.menuButtonWasTapped(response: CreditsModels.MenuButtonTapped.Response())     }      \/\/ MARK: - Analytics      func sendMenuButtonAnalytics(request: CreditsModels.AnalyticsData.Request) {         presenter?.sendButtonsAnalytics(response: CreditsModels.AnalyticsData.Response())          if let type = request.buttonType {             AnalyticsManager.shared.sendAutoplayButtonWasTapped(buttonType: type, event: analyticsEventForCurrent, isAutomatically: request.isAutomatically)         }     }      func sendButtonShowsAnalytics(request: CreditsModels.AnalyticsData.Request) {         presenter?.sendButtonsAnalytics(response: CreditsModels.AnalyticsData.Response())          var event: Analytics.PlaybackButtonsEvent?         switch request.buttonType {         case .nextMovie:             event = analyticsEventForRecommended         case .skipIntro, .nextEpisode, .some(.showCredits), .closeAutoplay, .none:             event = analyticsEventForCurrent         }         AnalyticsManager.shared.sendAutoplayButtonWasShown(buttonType: request.buttonType, event: event)     }      func sendButtonWasTappedAnalytics(request: CreditsModels.AnalyticsData.Request) {         presenter?.sendButtonsAnalytics(response: CreditsModels.AnalyticsData.Response())          AnalyticsManager.shared.sendAutoplayButtonWasTapped(buttonType: request.buttonType, event: analyticsEventForCurrent, isAutomatically: request.isAutomatically)     } }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0447\u0430\u0441\u0442\u044c \u2013 \u044d\u0442\u043e \u043d\u0430\u0448 <strong>Presenter<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code>final class CreditsPresenter {     private typealias \u0421reditsViewModel = (creditsType: AIVCreditsType?,                                           nextButtonTitle: AIVCreditsNextButtonTitle?,                                           toTime: Double?,                                           animationDuration: Int,                                           state: NextSimilarContentDescriptionStack.NextSimilarContentDescriptionState,                                           isBackgroundPosterHidden: Bool,                                           playerState: VODPlayerState)      weak var view: CreditsDisplayLogic?      private let skipIntroTimeInterval: TimeInterval = 5     private var currentContentType: ContentType?     private var currentChapterID: String?     private var posterPath: String?     private var isMoviesAutoplayShouldBeShown: Bool = true     private var didContentEnd: Bool = false     private var shouldBeHidden: Bool = false     private var isControlsHidden: Bool = true     private var isTimerStarted: Bool = false     private var creditsType: AIVCreditsType?     private lazy var currentCreditsViewModel: CreditsPresenter.\u0421reditsViewModel = defaultChapter()      private var isHidden: Bool {         if shouldBeHidden {             return true         }         if isControlsHidden &amp;&amp;             (creditsType == .tail ||              creditsType == .tailOnlyNextWithAnimation ||              isTimerStarted) {             return false         }         return isControlsHidden || creditsType == nil     }      private func tailCredits(animationDuration: Int, isControlsShown: Bool, isFirstCheck: Bool) -> \u0421reditsViewModel {         switch currentContentType {         case .serial:             \/\/ TODO: \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0444\u043b\u0430\u0433 \u0441 \u0431\u044d\u043a\u0430             guard MovieStoriesManager.shared.needsToShowTailCredit else {                 return defaultChapter()             }             return tailCreditsModelForSerials(animationDuration: animationDuration, isControlsInFocus: isControlsShown)         case .movie:             guard isMoviesAutoplayShouldBeShown else {                 return defaultChapter()             }             return tailCreditsModelForMovies(animationDuration: animationDuration, isControlsInFocus: isControlsShown)         case nil, .some(.none):             return defaultChapter()         }     }      private func headCredits(endTime: Double) -> \u0421reditsViewModel {         creditsType = .head         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: nil,                                 toTime: endTime,                                 animationDuration: 0,                                 state: .hidden,                                 isBackgroundPosterHidden: true,                                 playerState: .normal)     }      private func tailCreditsModelForSerials(animationDuration: Int, isControlsInFocus: Bool) -> \u0421reditsViewModel {         creditsType = isControlsInFocus ? .tailOnlyNextWithoutAnimation : .tail         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: .nextEpisode,                                 toTime: nil,                                 animationDuration: animationDuration,                                 state: .hidden,                                 isBackgroundPosterHidden: false,                                 playerState: .normal)     }      private func tailCreditsModelForMovies(animationDuration: Int, isControlsInFocus: Bool) -> \u0421reditsViewModel {         creditsType = isControlsInFocus ? .tailOnlyNextWithoutAnimation : .tail         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: .nextMovie,                                 toTime: nil,                                 animationDuration: animationDuration,                                 state: isControlsInFocus ? .shownOnlyTitle : .shownAll,                                 isBackgroundPosterHidden: isControlsInFocus,                                 playerState: isControlsInFocus ? .normal : .minimized)     }      private func defaultChapter() -> \u0421reditsViewModel {         creditsType = nil         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: nil,                                 toTime: nil,                                 animationDuration: 0,                                 state: .hidden,                                 isBackgroundPosterHidden: true,                                 playerState: .normal)     }      private func closingPlayerModel() -> \u0421reditsViewModel {         creditsType = nil         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: nil,                                 toTime: nil,                                 animationDuration: 0,                                 state: .hidden,                                 isBackgroundPosterHidden: true,                                 playerState: .closed)     }      private func nextMovieModel(type: AIVCreditsType?, animationDuration: Int) -> \u0421reditsViewModel {         creditsType = type         return \u0421reditsViewModel(creditsType: creditsType,                                 nextButtonTitle: .nextMovie,                                 toTime: nil,                                 animationDuration: animationDuration,                                 state: .shownAll,                                 isBackgroundPosterHidden: false,                                 playerState: .hidden)     } }  extension CreditsPresenter: CreditsPresentationLogic {     func updateGradientFrame(response: CreditsModels.GradientFrameUpdates.Response) {         view?.updateGradientFrame(viewModel: CreditsModels.GradientFrameUpdates.ViewModel(frame: response.frame))     }      func moveView(response: CreditsModels.MoveView.Response) {         let viewModel = CreditsModels.MoveView.ViewModel(transform: CGAffineTransform(translationX: 0, y: response.inset))         view?.moveView(viewModel: viewModel)     }      func bringSubviewToFront(response: CreditsModels.LayoutUpdates.Response) {         view?.bringSubviewToFront(viewModel: CreditsModels.LayoutUpdates.ViewModel())     }      func updateData(response: CreditsModels.UpdateAutoplayData.Response) {         didContentEnd = false         currentContentType = response.currentContentType         isMoviesAutoplayShouldBeShown = response.isMoviesAutoplayShouldBeShown          let viewModel = CreditsModels.UpdateAutoplayData.ViewModel(info: response.info, path: response.path)         view?.updateData(viewModel: viewModel)     }      func didFindChapter(response: CreditsModels.SearchCurrentChapter.Response) {         guard currentChapterID != response.chapter?.ID else {             return         }          \/\/ \u0435\u0441\u043b\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f - \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u043f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0430\u0445 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b         let isControlsShown = response.isFirstCheck ? true : response.isControlsShown          currentChapterID = response.chapter?.ID         switch response.chapterType {         case .headCredit:             guard let endOffsetTime = response.chapter?.endOffsetTime?.doubleValue else {                 return             }             currentCreditsViewModel = headCredits(endTime: endOffsetTime)         case .tailCredit:             currentCreditsViewModel = tailCredits(animationDuration: response.animationDuration,                                                   isControlsShown: isControlsShown || shouldBeHidden,                                                   isFirstCheck: response.isFirstCheck)         case nil, .some(.movieStorySuperEpisodeChapter), .some(.none):             if let type = creditsType,                AIVCreditsType.tailsChaptersWithAnimation.contains(type) {                 \/\/ \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439, \u0434\u0430\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0434\u043e\u0438\u0433\u0440\u0430\u0442\u044c \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u0447\u0430\u043f\u0442\u0435\u0440\u044b \u043d\u0435 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u043c                 return             }             currentCreditsViewModel = defaultChapter()         }          let shouldShowControls = response.isFirstCheck &amp;&amp; creditsType == .tailOnlyNextWithoutAnimation         let viewModel = CreditsModels.SearchCurrentChapter.ViewModel(creditsType: currentCreditsViewModel.creditsType,                                                                      nextButtonTitle: currentCreditsViewModel.nextButtonTitle,                                                                      toTime: currentCreditsViewModel.toTime,                                                                      animationDuration: currentCreditsViewModel.animationDuration,                                                                      state: currentCreditsViewModel.state,                                                                      isBackgroundPosterHidden: currentCreditsViewModel.isBackgroundPosterHidden,                                                                      playerState: currentCreditsViewModel.playerState,                                                                      isHidden: isHidden,                                                                      shouldShowControls: shouldShowControls)         view?.updateCreditsView(viewModel: viewModel)     }      func skipIntro(response: CreditsModels.SkipIntro.Response) {         view?.skipIntro(viewModel: CreditsModels.SkipIntro.ViewModel(time: response.time))     }      func didContentEnd(response: CreditsModels.UpdateCreditsType.Response) {         didContentEnd = true         if isMoviesAutoplayShouldBeShown {             creditsType = shouldBeHidden ? .tailOnlyNextWithoutAnimation : .tailOnlyNextWithAnimation             currentCreditsViewModel = nextMovieModel(type: creditsType, animationDuration: response.animationDuration)         } else {             \/\/ \u0435\u0441\u043b\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d, \u043d\u0435 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043f\u043b\u0435\u0435\u0440, \u043f\u043e\u043a\u0430 \u043f\u043e\u043b\u043a\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u0430             if shouldBeHidden {                 return             }             currentCreditsViewModel = closingPlayerModel()         }          let viewModel = CreditsModels.UpdateCreditsType.ViewModel(creditsType: currentCreditsViewModel.creditsType,                                                                   nextButtonTitle: currentCreditsViewModel.nextButtonTitle,                                                                   toTime: currentCreditsViewModel.toTime,                                                                   animationDuration: currentCreditsViewModel.animationDuration,                                                                   state: currentCreditsViewModel.state,                                                                   isBackgroundPosterHidden: currentCreditsViewModel.isBackgroundPosterHidden,                                                                   playerState: currentCreditsViewModel.playerState,                                                                   isHidden: isHidden)         view?.updateCreditsView(viewModel: viewModel)     }      func showCredits(response: CreditsModels.UpdateCreditsType.Response) {         let creditsViewModel = tailCredits(animationDuration: 0, isControlsShown: true, isFirstCheck: false)         currentCreditsViewModel = creditsViewModel         let viewModel = CreditsModels.UpdateCreditsType.ViewModel(creditsType: currentCreditsViewModel.creditsType,                                                                   nextButtonTitle: currentCreditsViewModel.nextButtonTitle,                                                                   toTime: currentCreditsViewModel.toTime,                                                                   animationDuration: currentCreditsViewModel.animationDuration,                                                                   state: currentCreditsViewModel.state,                                                                   isBackgroundPosterHidden: currentCreditsViewModel.isBackgroundPosterHidden,                                                                   playerState: currentCreditsViewModel.playerState,                                                                   isHidden: isHidden)         view?.showCredits(viewModel: viewModel)     }      func playNext(response: CreditsModels.NextButtonDidPress.Response) {         let creditsViewModel = defaultChapter()         currentCreditsViewModel = creditsViewModel         let viewModel = CreditsModels.NextButtonDidPress.ViewModel(isAuto: response.isAuto,                                                                    creditsType: currentCreditsViewModel.creditsType,                                                                    nextButtonTitle: currentCreditsViewModel.nextButtonTitle,                                                                    toTime: currentCreditsViewModel.toTime,                                                                    animationDuration: currentCreditsViewModel.animationDuration,                                                                    state: currentCreditsViewModel.state,                                                                    isBackgroundPosterHidden: currentCreditsViewModel.isBackgroundPosterHidden,                                                                    playerState: currentCreditsViewModel.playerState,                                                                    isHidden: isHidden)         view?.playNext(viewModel: viewModel)     }      func visibilityShouldBeChanged(response: CreditsModels.UpdateVisibility.Response) {         shouldBeHidden = response.shouldBeHidden         \/\/ \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u043a\u0430 \u0437\u0430\u043a\u0440\u044b\u043b\u0430\u0441\u044c \u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0434\u043e\u0438\u0433\u0440\u0430\u043b \u0434\u043e \u043a\u043e\u043d\u0446\u0430 - \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u043a\u0440\u0430\u043d \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f         if !shouldBeHidden, didContentEnd {             switch creditsType {             case .tailOnlyNextWithoutAnimation:                 \/\/ \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430, \u043f\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438 \u043f\u043e\u043b\u043a\u0438 \u043f\u043e\u0445\u043e\u0436\u0438\u0445 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0441\u043e \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u043e\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f                 currentCreditsViewModel = nextMovieModel(type: .tailOnlyNextWithAnimation, animationDuration: response.animationDuration)             case .tailOnlyNextWithAnimation, .tail, .playNext, .head, .none:                 \/\/ \u0435\u0441\u043b\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430, \u043f\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438 \u043f\u043e\u043b\u043a\u0438 \u043f\u043e\u0445\u043e\u0436\u0438\u0445 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043f\u043b\u0435\u0435\u0440                 if !isMoviesAutoplayShouldBeShown {                     currentCreditsViewModel = closingPlayerModel()                 }             }         }         let viewModel = CreditsModels.UpdateVisibility.ViewModel(creditsType: currentCreditsViewModel.creditsType,                                                                  nextButtonTitle: currentCreditsViewModel.nextButtonTitle,                                                                  toTime: currentCreditsViewModel.toTime,                                                                  animationDuration: currentCreditsViewModel.animationDuration,                                                                  state: currentCreditsViewModel.state,                                                                  isBackgroundPosterHidden: currentCreditsViewModel.isBackgroundPosterHidden,                                                                  playerState: currentCreditsViewModel.playerState,                                                                  isHidden: isHidden)         view?.updateVisibility(viewModel: viewModel)     }      func controlsVisibilityChanged(response: CreditsModels.ControlsVisibilityWasChanged.Response) {         isControlsHidden = response.isControlsHidden         let viewModel = CreditsModels.ControlsVisibilityWasChanged.ViewModel(isControlsHidden: isControlsHidden,                                                                              isHidden: isHidden)         view?.controlsVisibilityChanged(viewModel: viewModel)     }      func updateTimer(response: CreditsModels.UpdateTimer.Response) {         isTimerStarted = response.shouldTimerStart         let viewModel = CreditsModels.UpdateTimer.ViewModel(skipIntroTimeInterval: skipIntroTimeInterval, isHidden: isHidden)         if isTimerStarted {             view?.startTimer(viewModel: viewModel)         } else {             view?.dropTimer(viewModel: viewModel)         }     }      func menuButtonWasTapped(response: CreditsModels.MenuButtonTapped.Response) {         var buttonType: AIVAnalyticsKeys.ButtonTypes?         var isAutomatically: Bool?          switch creditsType {         case .tail, .tailOnlyNextWithAnimation:             buttonType = .closeAutoplay             isAutomatically = false         case .head, .playNext, .none, .some(.tailOnlyNextWithoutAnimation):             buttonType = nil             isAutomatically = nil         }          var currentViewModel: \u0421reditsViewModel         if isTimerStarted {             currentViewModel = defaultChapter()         } else {             currentViewModel = closingPlayerModel()         }          let viewModel = CreditsModels.MenuButtonTapped.ViewModel(buttonType: buttonType,                                                                  isAutomatically: isAutomatically,                                                                  creditsType: currentViewModel.creditsType,                                                                  nextButtonTitle: currentViewModel.nextButtonTitle,                                                                  toTime: currentViewModel.toTime,                                                                  animationDuration: currentViewModel.animationDuration,                                                                  state: currentViewModel.state,                                                                  isBackgroundPosterHidden: currentViewModel.isBackgroundPosterHidden,                                                                  playerState: currentViewModel.playerState)         view?.menuButtonWasTapped(viewModel: viewModel)     }      func sendButtonsAnalytics(response: CreditsModels.AnalyticsData.Response) {         view?.sendButtonsAnalytics(viewModel: CreditsModels.AnalyticsData.ViewModel())     } }<\/code><\/pre>\n<p>\u041d\u0443 \u0438 \u043d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 <strong>Builder<\/strong>, \u0435\u0434\u0438\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>protocol CreditsBuildingLogic: AnyObject {     func makeCreditsModule(delegate: CreditsViewDelegate?) -> CreditsViewController }  final class CreditsBuilder: CreditsBuildingLogic {     func makeCreditsModule(delegate: CreditsViewDelegate?) -> CreditsViewController {         let view = CreditsViewController()         let presenter = CreditsPresenter()         let interactor = CreditsInteractor(with: ChapterWorker(), remoteConfigWorker: AIVRemoteConfigWorker())          interactor.presenter = presenter         presenter.view = view          view.delegate = delegate         view.interactor = interactor          return view     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/94b\/c5d\/53e\/94bc5d53e447ae902eb7710c592dd670.png\" alt=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 14 -  \u0413\u043e\u0442\u043e\u0432\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0444\u0438\u0447\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" title=\"\u0420\u0438\u0441\u0443\u043d\u043e\u043a 14 -  \u0413\u043e\u0442\u043e\u0432\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0444\u0438\u0447\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f\" width=\"1600\" height=\"779\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/94b\/c5d\/53e\/94bc5d53e447ae902eb7710c592dd670.png\"\/><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 14 &#8212;  \u0413\u043e\u0442\u043e\u0432\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0444\u0438\u0447\u0438 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0422\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 (\u043a\u0430\u043a \u043c\u0435\u0436\u0434\u0443 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438, \u0442\u0430\u043a \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0446\u0435\u043d) \u0431\u044b\u043b\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0430, \u043d\u043e \u0438 \u043d\u0435 \u0442\u044f\u043d\u0443\u0442\u044c\u0441\u044f \u0437\u0430 \u043f\u0443\u043b\u044c\u0442\u043e\u043c, \u0447\u0442\u043e\u0431 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u0445\u043e\u0436\u0438\u0439 \u0444\u0438\u043b\u044c\u043c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u043d\u044b\u043d\u0435\u0448\u043d\u0435\u0433\u043e.<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u0430\u043c \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0441\u0442\u0430\u043b\u0430 \u0434\u043b\u044f \u0432\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0438 \u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c! <strong>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438\u043b\u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f \u2013 \u0436\u0434\u0443 \u0432\u0430\u0441 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445<\/strong>. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/692074\/\"> https:\/\/habr.com\/ru\/articles\/692074\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0412\u0430\u043b\u0435\u0440\u0438\u044f \u0420\u0443\u0431\u043b\u0435\u0432\u0441\u043a\u0430\u044f, \u044f iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043d\u043b\u0430\u0439\u043d-\u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 <a href=\"https:\/\/kion.ru\/home\">KION<\/a> \u0432 <a href=\"https:\/\/career.habr.com\/companies\/mts\/vacancies\">\u041c\u0422\u0421 Digital<\/a>. \u042d\u0442\u043e \u0442\u0440\u0435\u0442\u044c\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430 \u043e \u0444\u0438\u0447\u0435 Autoplay \u0444\u0438\u043b\u044c\u043c\u043e\u0432 \u0438 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u043d\u044e\u0430\u043d\u0441\u0430\u0445 \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 tvOS.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e Autoplay \u2013 \u044d\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0441\u0430\u043c\u043e\u0439 \u0444\u0438\u0447\u0435 \u0440\u0430\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043c\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u0433\u0430 \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0435\u043b\u044c\u043d\u0438\u043a\u043e\u0432 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/681456\/\"><u>\u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/u><\/a>.<\/p>\n<p><em>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440: \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u0438 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u044f, \u0446\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2013 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u0438\u0442\u044c \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/em><\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e \u0432 \u0441\u0435\u0440\u0438\u0430\u043b\u0430\u0445.<\/p>\n<p>\u0422\u0430\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043b\u043e\u0436\u0438\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0432 KION \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0434\u043b\u044f iOS \u0438 tvOS. \u041f\u0440\u043e\u0435\u043a\u0442\u044b \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u0438 \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0434\u0440\u0443\u0433 \u043a \u0434\u0440\u0443\u0433\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0441\u0432\u043e\u044f, \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 tvOS.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0443, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0442\u0438\u0442\u0440\u044b. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0440\u044f\u0434 \u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0445 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u043d \u0432\u044b\u0439\u0434\u0435\u0442 \u0438\u0437 \u043f\u043b\u0435\u0435\u0440\u0430, \u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.\u00a0<\/p>\n<p>\u041d\u043e \u0436\u0434\u0430\u0442\u044c, \u043f\u043e\u043a\u0430 \u043c\u044b \u0440\u0430\u0437\u043c\u0435\u0442\u0438\u043c \u0432\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u0422\u0430\u043a \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0434\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430. \u0414\u0438\u0437\u0430\u0439\u043d\u0435\u0440\u044b \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043b\u0438 \u0442\u0430\u043a\u0438\u0435 \u043c\u0430\u043a\u0435\u0442\u044b: <\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 1 &#8212; \u0410\u0432\u0442\u043e\u043f\u043b\u0435\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430, \u043a\u043e\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432<\/figcaption><\/figure>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 2 &#8212; \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b<\/figcaption><\/figure>\n<p>\u041a\u043d\u043e\u043f\u043a\u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u043a \u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438. \u041f\u0440\u043e \u0444\u0438\u0447\u0443 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0442\u0438\u0442\u0440\u043e\u0432 \u0440\u0430\u043d\u0435\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u043c\u043e\u0438 \u043a\u043e\u043b\u043b\u0435\u0433\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/661531\/\">\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0435\u043b\u044c\u043d\u0438\u043a\u043e\u0432<\/a> \u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ru_mts\/blog\/671922\/\">\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041e\u0445\u0440\u0438\u043c\u0435\u043d\u043a\u043e.<\/a>\u00a0<\/p>\n<p>\u041d\u0430 \u043c\u0430\u043a\u0435\u0442\u0430\u0445 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043a\u043d\u043e\u043f\u043a\u0438 <strong>\u0421\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0438\u0442\u0440\u044b<\/strong> \u0438 <strong>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c<\/strong> \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u043c\u0435\u0442\u0440\u0430\u0436\u0435\u043a \u0442\u0430\u043a\u0438\u0435 \u0436\u0435, \u043a\u0430\u043a \u0438 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432. \u0410 \u0437\u043d\u0430\u0447\u0438\u0442, \u044d\u0442\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u0418 \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0430\u0441\u044c, \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u0432 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u2013 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c <strong>PlayerViewController<\/strong> \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0437\u0430 \u0432\u0441\u0435: \u0441\u0430\u043c\u043e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 (\u0441\u0440\u0435\u0434\u0441\u0442\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u043e\u043c), \u043a\u043d\u043e\u043f\u043a\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0435\u0440\u0438\u0438. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043d\u0438\u0436\u0435.<\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 3 &#8212; \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u043f\u043b\u0435\u0435\u0440\u0435<\/figcaption><\/figure>\n<p>\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043f\u043e\u0441\u0442\u0435\u0440 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430 \u043d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d, \u043f\u043e\u0432\u0435\u0440\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u043c\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u0430\u043c \u043f\u043b\u0435\u0435\u0440 \u2013 \u0432 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435, \u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b \u0441\u043a\u0440\u044b\u0442\u044b. \u0412 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0443 \u0442\u0438\u0442\u0440\u043e\u0432 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c.\u00a0<\/p>\n<p>\u0414\u0435\u043b\u0435\u0433\u0430\u0442, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0438\u044f\u043c\u0438 \u2013 <strong>creditsViewDelegate<\/strong> \u2013 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u043e\u0432\u0440\u0435\u043c\u044f \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e. \u041e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0435\u0449\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 \u043f\u043b\u0435\u0435\u0440\u0430, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u0438\u043b\u044c\u043c\u0435 \u0438 \u0443\u043c\u0435\u0442\u044c \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b \u043e\u0442 \u0444\u0438\u043b\u044c\u043c\u0430. \u0412\u0435\u0434\u044c \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u0431\u0435\u0437 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043a\u043e\u0434\u0430 \u044f \u0440\u0435\u0448\u0438\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0437\u043e\u043d\u0430\u043c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438.\u00a0 \u041f\u043e\u0441\u043b\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430, \u0441 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438:<\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 4 &#8212; \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438<\/figcaption><\/figure>\n<p>\u0413\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>PlayerViewControllerProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p><strong>PlayerControlViewControllerProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0430\u043c\u0438 (\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c, \u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0430 \u043f\u0430\u0443\u0437\u0443, \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430);<\/p>\n<\/li>\n<li>\n<p><strong>CreditsViewProtocol<\/strong> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 (\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0438\u044f\u043c\u0438, \u043f\u0440\u043e\u043f\u0443\u0441\u043a \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c).<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043a\u043b\u0430\u0441\u0441 <strong>PlayerViewContainerController<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0438\u043c\u0438 \u0442\u0440\u0435\u043c\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c. \u0410 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0438\u0447\u0438 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0449\u0435.<\/p>\n<p>\u041f\u043e\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u0441\u044f \u0433\u043b\u0443\u0431\u0436\u0435 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u0440\u0438\u044e \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438. \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u043a\u0430\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 <strong>MetaChapter<\/strong>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0444\u0438\u0447\u0435-\u0444\u043b\u0430\u0433\u043e\u043c.<\/p>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 (\u043d\u0430\u0447\u0430\u043b\u043e \u0438 \u043a\u043e\u043d\u0435\u0446 \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u0438 \u0442\u0438\u0442\u0440\u043e\u0432).<\/p>\n<figure class=\"\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 5 &#8212; \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439<\/figcaption><\/figure>\n<p>\u0412\u0432\u0435\u0434\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u0435\u043c:<\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 6 &#8212; \u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f, \u0437\u0430 \u0447\u0442\u043e \u0436\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <strong>CreditsViewController<\/strong> \u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u0430\u043a\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043d\u0438\u043c \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043f\u043e \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0443, \u043d\u0430\u0448\u043b\u0430\u0441\u044c \u043b\u0438 \u0443 \u043d\u0430\u0441 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f (\u041f\u0440\u043e\u043f\u0443\u0441\u043a \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438, \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0435\u0440\u0438\u044f, \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0438\u043b\u044c\u043c);<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\/\u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043b\u0435\u0435\u0440\u0430 (\u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c, \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c, \u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c);<\/p>\n<\/li>\n<li>\n<p>\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u043e\u0439, \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0435\u0440 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0438\u043b\u044c\u043c\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u0438\u043b\u044c\u043c\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044e \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e UI-\u0441\u043b\u043e\u044f. \u041a\u0430\u043a\u0430\u044f-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438\u0448\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432\u043e\u0432\u043d\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0432\u043e\u0440\u043a\u0435\u0440 ChapterWorker, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c <strong>ChapterWorkingLogic<\/strong>:<\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 7 &#8212; \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0439 \u0444\u0438\u0447\u0438:<\/p>\n<pre><code>final class ChapterWorker {     private var chapters: [MetaChapter]? }  extension ChapterWorker: ChapterWorkingLogic {  \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0430\u043f\u0442\u0435\u0440\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441 \u0444\u0438\u043b\u044c\u043c\u0430 \u043d\u0430 \u0444\u0438\u043b\u044c\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u043b\u0435\u0435\u0440\u0435, \u0442\u0430\u043a \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430, \u043c\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043b\u0438\u0448\u044c \u0447\u0430\u043f\u0442\u0435\u0440\u044b     func updateCurrentChapters(chapters: [MetaChapter]?) {         self.chapters = chapters     }  \/\/ \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0432\u0445\u043e\u0434\u0438\u0442 \u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u043e\u0434\u0438\u043d \u0438\u0437 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u043e\u0432     func chapter(currentTime: Double) -> MetaChapter? {         let chapter = chapters?.first(where: {             guard let offTimeString = $0.offTime,                   let endOffsetTimeString = $0.endOffsetTime,                   let offTime = Int(offTimeString),                   let endOffsetTime = Int(endOffsetTimeString),                   offTime &lt; (endOffsetTime - 1) else { return false }             return (offTime..&lt;endOffsetTime) ~= Int(floor(currentTime))         })         return chapter     }  \/\/\u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0442\u0438\u043f\u0430 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 (\u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430, \u0442\u0438\u0442\u0440\u044b, \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e)     func chapterType(chapter: MetaChapter?) -> AIVChaptersType {         guard let title = chapter?.title else {             return .none         }         return AIVChaptersType(rawValue: title) ?? .none     } }<\/code><\/pre>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u2013 \u0442\u043e, \u043a\u0430\u043a \u0438 \u043e\u0442\u043a\u0443\u0434\u0430 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0447\u0442\u043e \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 EPlayerView \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0441 \u0442\u0430\u0439\u043c\u0435\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435:<\/p>\n<pre><code>private func addPeriodicTimeObserver() {     if timeObserverToken == nil {         let interval = CMTime(seconds: EPlayerView.periodicTimeInterval, preferredTimescale: CMTimeScale(NSEC_PER_SEC))         timeObserverToken = avPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main) { [weak self] _ in             guard let self = self else {                 return             }             let presentationSize = self.avPlayer?.currentItem?.presentationSize             self.presentationSizeDelegate?.updated(presentationSize: presentationSize)             self.playbackDelegate?.updated(presentationSize: presentationSize)             self.updatePlaybackDataIfNeeded(for: self.type, self.avPlayer?.currentItem)             self.notifyAboutAccessLogEntryIfNeeded(self.avPlayer?.currentItem)         }     } }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0442\u0430\u0439\u043c\u043a\u043e\u0434\u0430 \u043e\u043f\u0438\u0441\u0430\u043d \u043d\u0438\u0436\u0435:<\/p>\n<pre><code>private func updatePlaybackDataIfNeeded(for type: EPlayerViewType, _ currentItem: AVPlayerItem?) {     switch type {     case .vod, .trailer:         guard let currentItem = currentItem else {             return         }         delegate?.update(min: 0)         delegate?.update(max: currentItem.duration.seconds)         delegate?.update(current: currentItem.currentTime().seconds)         let currentTimeInSeconds = floor(currentItem.currentTime().seconds)         if floor(chapterTimerCounter) != currentTimeInSeconds {             chapterTimerCounter = currentTimeInSeconds             playbackDelegate?.updateChaptersWithTime(current: currentTimeInSeconds)         }     default:         guard let currentDate = avPlayer?.currentItem?.currentDate() else {             return         }         if let s = startDate {             self.delegate?.update(start: s)         }         if let e = endDate {             self.delegate?.update(end: e)         }         delegate?.update(current: currentDate)         NotificationCenter.default.post(name: .livePlayerDidUpdateTimeNotification,                                         object: nil,                                         userInfo: [EPlayerView.keyFTS: currentDate.timeIntervalSince1970])     }     playbackDelegate?.playerPlaybackStateDidChange(to: playbackState) }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0433\u0434\u0435 <strong>chapterTimerCounter<\/strong> \u2013 \u0441\u0447\u0435\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u043e\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u0442\u0440\u043e\u0432, \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u044b\u0448\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 ChapterWorker.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0414\u0430\u043b\u0435\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441 \u0441\u0430\u043c\u0438\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u043c \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f:<\/p>\n<figure class=\"full-width\"><figcaption>\u0420\u0438\u0441\u0443\u043d\u043e\u043a 8 &#8212; \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0430\u0432\u0442\u043e\u043f\u043b\u0435\u044f<\/figcaption><\/figure>\n<p>\u0413\u0434\u0435:<\/p>\n<ul>\n<li>\n<p><strong>buttonsView<\/strong> \u2013 \u043a\u043d\u043e\u043f\u043a\u0438 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0444\u043e\u043a\u0443\u0441\u0430 \u043c\u0435\u0436\u0434\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043a\u043d\u043e\u043f\u043e\u043a \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043e\u0432 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 UIFocusGuide;\u00a0<\/p>\n<\/li>\n<li>\n<p><strong>updateAutoplayData(&#8230;)<\/strong> \u2013 <\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-401607","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/401607","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=401607"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/401607\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=401607"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=401607"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=401607"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}