{"id":198258,"date":"2013-10-21T22:39:03","date_gmt":"2013-10-21T18:39:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=198258"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=198258","title":{"rendered":"<span class=\"post_title\">\u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u043a\u0430\u0447\u0430\u043b \u043c\u0443\u0437\u044b\u043a\u0443 \u0441 VK<\/span>"},"content":{"rendered":"<div class=\"content html_format\">\n<h4>\u041f\u0440\u0435\u0434\u0438\u0441\u0442\u043e\u0440\u0438\u044f<\/h4>\n<p>  \u041a\u0430\u0436\u0434\u043e\u0435 \u0443\u0442\u0440\u043e \u044f \u0435\u0437\u0436\u0443 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0438 \u044d\u0442\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 <s>N-\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/s> \u043e\u0442 15 \u043c\u0438\u043d\u0443\u0442 (\u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0435) \u0434\u043e 40 \u043c\u0438\u043d\u0443\u0442 (\u043d\u0430 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0435). \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0443\u0442\u0440\u043e\u043c \u043f\u043e \u0440\u0430\u0434\u0438\u043e \u043a\u0440\u0443\u0442\u044f\u0442 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043c\u0443\u0437\u044b\u043a\u0443, \u0430 \u0440\u0430\u0437\u043d\u044b\u0435 \u00ab\u0440\u0430\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435\u00bb \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u041e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u044f \u0435\u0437\u0434\u0438\u043b \u043b\u0438\u0431\u043e \u0441 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u043c\u0430\u0433\u043d\u0438\u0442\u043e\u0444\u043e\u043d\u043e\u043c, \u043b\u0438\u0431\u043e \u0432\u0441\u044e \u0434\u043e\u0440\u043e\u0433\u0443 \u0438\u0441\u043a\u0430\u043b \u0440\u0430\u0434\u0438\u043e\u0441\u0442\u0430\u043d\u0446\u0438\u044e, \u043b\u0438\u0431\u043e \u0432\u0440\u0443\u0431\u0430\u043b \u043d\u0430\u0443\u0448\u043d\u0438\u043a\u0438 (\u043f\u043e\u043a\u0430 \u043d\u0435 \u0440\u0430\u0437\u0434\u0430\u0432\u0438\u043b \u0441\u0432\u043e\u0439 \u0442\u0435\u043b\u0435\u0444\u043e\u043d).<\/p>\n<p>  \u0418 \u0432\u043e\u0442 \u043c\u043d\u0435 \u044d\u0442\u043e \u043d\u0430\u0434\u043e\u0435\u043b\u043e. \u041c\u0430\u0433\u043d\u0438\u0442\u043e\u043b\u0430 \u0443 \u043c\u0435\u043d\u044f \u0438\u0437 \u0434\u0435\u0448\u0435\u0432\u044b\u0445, \u043d\u043e \u0443\u043c\u0435\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0441 \u0444\u043b\u0435\u0448\u0435\u043a. \u0412 \u043e\u0434\u0438\u043d \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0434\u0435\u043d\u044c, \u043f\u043e \u0434\u043e\u0440\u043e\u0433\u0435 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443, \u044f \u0432\u0437\u044f\u043b \u0438 \u043a\u0443\u043f\u0438\u043b SD-\u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0443 (\u0443\u0434\u043e\u0431\u043d\u0435\u0439 \u0432\u0441\u0435\u0433\u043e \u0438\u0431\u043e \u043d\u0435 \u0432\u044b\u043f\u0438\u0440\u0430\u0435\u0442). \u0412\u0441\u0435 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u043f\u0440\u043e\u0441 \u0441\u0442\u0430\u043b \u0438\u043d\u0430\u0447\u0435: \u00ab\u0413\u0434\u0435 \u0432\u0437\u044f\u0442\u044c \u043c\u0443\u0437\u044b\u043a\u0443?\u00bb. \u041d\u0435 \u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043c\u043d\u0435 \u0445\u0432\u0430\u0442\u0438\u0442 \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\u0430 \u0441 VK. \u0412\u0441\u0435\u0433\u043e-\u0442\u043e 400+ \u043f\u0435\u0441\u0435\u043d, \u043d\u043e \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043a\u0430\u0447\u0430\u0442\u044c.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435, \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0435. \u0421\u043e\u0437\u0434\u0430\u043b \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 django, \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0435\u0435 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 couchdb \u0438 \u043f\u0440\u0438\u043d\u044f\u043b\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c.<\/p>\n<h4>\u041f\u0440\u0438\u0447\u0438\u043d\u044b<\/h4>\n<p>  \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u0447\u0438\u043d, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0435, \u0430 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435.<br \/>   \u2014 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u043b\u0430\u0433\u0438\u043d\/\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0443 \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f<br \/>   \u2014 \u043a\u0430\u0447\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443<br \/>   \u2014 \u0434\u0430 \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0447\u0442\u043e-\u0442\u043e \u0441\u0432\u043e\u0435<\/p>\n<h4>\u0427\u0442\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c<\/h4>\n<p>  \u041e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442. \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439: \u0437\u0430\u0448\u0435\u043b \u043d\u0430 \u0441\u0430\u0439\u0442, \u0447\u0442\u043e-\u0442\u043e \u043d\u0430\u0436\u0430\u043b, \u0443\u0432\u0438\u0434\u0435\u043b \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0438, \u043d\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443, \u0441\u043a\u0430\u0447\u0430\u043b \u0438\u0445 \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440.<\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e (\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0445\u043e\u0434 \u0441\u043e\u0431\u044b\u0442\u0438\u0439).<\/p>\n<h4>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/h4>\n<p>  \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u044f\u043c \u0432\u0437\u044f\u043b \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 VK Api.<\/p>\n<p>  <b>\u042d\u0442\u0430\u043f \u21161.<\/b> \u0421\u043d\u0430\u0447\u0430\u043b\u0430 <i><b>\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/b><\/i> \u0438 <i><b>\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430<\/b><\/i>. (\u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c API VK \u0438\u0431\u043e \u0432\u0441\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0443 \u043d\u0438\u0445 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435).<br \/>  \u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442 \u0432 \u043f\u0430\u043f\u043a\u0435 \u0441 django-\u0430\u043f\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0444\u0430\u0439\u043b vkapi.py \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">vkapi.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def authorize():     payload = {         'client_id': settings.APP_ID,         'scope': ','.join(settings.APP_PERMISSIONS),         # TODO: \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0445         'redirect_uri': 'http:\/\/127.0.0.1:8000\/vkapi\/authorize',         'response_type': 'code',         'v': settings.APP_API_VERSION     }     return 'https:\/\/oauth.vk.com\/authorize?%s' % urllib.urlencode(payload) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0410 \u0432 \u0444\u0430\u0439\u043b views.py \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u044c\u044e\u0445\u0430:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">views.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def vk_authorize(request):     return redirect(authorize()) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0418\u0442\u0430\u043a \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 code, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u043d\u0430 redirect_url. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c access_token.<\/p>\n<p>  \u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u0435\u043d\u044f \u0432\u043e\u043b\u043d\u043e\u0432\u0430\u043b \u0432\u043e\u043f\u0440\u043e\u0441 \u0433\u0434\u0435 \u0435\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u0443\u043c\u0430\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f VK \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 access_token \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442, \u0438\u0431\u043e couchdb) \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041d\u043e \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u044f \u043d\u0435 \u0445\u043e\u0447\u0443 \u0432\u0445\u043e\u0434\u0438\u0442\u044c \u0438\u043b\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f\u2026 \u0425\u0432\u0430\u0442\u0438\u0442 \u0441\u0435\u0441\u0441\u0438\u0438. \u041d\u0435 \u0432\u0438\u0436\u0443 \u0441\u043c\u044b\u0441\u043b\u0430 \u0447\u0435\u0433\u043e-\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u043d\u0443\u0436\u0434.<\/p>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u043b\u0435\u043d\u044c \u0437\u0430\u0441\u0442\u0430\u043b\u0430 \u043c\u0435\u043d\u044f \u0432\u0440\u0430\u0441\u043f\u043b\u043e\u0445, \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c URL \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f access_token&#8217;a \u0438 \u0432\u044c\u044e\u0445\u0430 vk_authorize \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439, \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u0432\u0438\u0434:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">vk_authorize<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def vk_authorize(request):     # \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u044c     if request.GET.get('code'):         code = request.GET['code']         r = access_token_get(code)         print r.text         data = r.json()                  if data.get('error'):             raise Http404(&quot;Error: %s. Desc: %s&quot; % (data['error'], data['error_description']))                  data['date'] = datetime.now()         request.session['vkapi'] = data         return redirect('main')              elif request.GET.get('error'):         error = request.GET['error']         error_description = request.GET.get('error_description')         raise Http404(&quot;Error: %s. Desc: %s&quot; % (error, error_description)) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0430 \u0432 vkapi.py \u0434\u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f access_token&#8217;a  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">access_token<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def access_token_get(code):     payload = {         'client_id': settings.APP_ID,         'client_secret': settings.APP_SECRET,         'code': code,         'redirect_uri': 'http:\/\/127.0.0.1:8000\/vkapi\/authorize',     }          return requests.get('https:\/\/oauth.vk.com\/access_token', params=payload) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <b>\u042d\u0442\u0430\u043f \u21162.<\/b> \u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c access_token \u0438 \u043f\u0438\u0448\u0435\u043c \u0435\u0433\u043e \u0432 \u0441\u0435\u0441\u0441\u0438\u044e. \u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0438. \u0422\u0430\u043a \u0432 \u0444\u0430\u0439\u043b vkapi.py \u0434\u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0435\u0449\u0435 \u0434\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041e\u0434\u043d\u0430 \u043e\u0431\u0449\u0430\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 api \u0432\u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435, \u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">vkapi.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def request_api(method, access_token, params):     &quot;&quot;&quot;     \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 API \u0412\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u0435, \u0412\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c     POST \u0438\u043b\u0438 GET \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 HTTPS \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 URL:     https:\/\/api.vk.com\/method\/'''METHOD_NAME'''?'''PARAMETERS'''&access_token='''ACCESS_TOKEN'''          METHOD_NAME \u2013 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 API (http:\/\/vk.com\/dev\/methods),     PARAMETERS \u2013 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 API,     ACCESS_TOKEN \u2013 \u043a\u043b\u044e\u0447 \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.     &quot;&quot;&quot;     payload = {         'access_token': access_token,         'v': settings.APP_API_VERSION,     }     payload.update(params)     r = requests.get('https:\/\/api.vk.com\/method\/%s' % method, params=payload)     return r.json().get('response', {})   def audio_get(session):          params = {         'owner_id': session['user_id'],         'count': 6000,     }     return request_api('audio.get', session['access_token'], params) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0424\u0430\u0439\u043b views.py \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u043e\u043f\u043e\u043b\u043d\u0438\u043b\u0441\u044f \u0435\u0449\u0435 \u043e\u0434\u043d\u043e\u0439 \u0432\u044c\u044e\u0445\u043e\u0439:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">vk_audios<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">@render_to(&quot;downloader\/vk_audios.html&quot;) def vk_audios(request):     audios = []     if request.session.get('vkapi'):         # TODO: \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c access_token         audios = audio_get(request.session['vkapi'])              return {         'audios': audios,     } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0441\u0432\u043e\u0438\u0445 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0411\u044b\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0435\u0449\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0430\u043b\u044c\u0431\u043e\u043c\u043e\u0432 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0445 \u043f\u0435\u0441\u0435\u043d, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u041c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u0447\u0442\u043e \u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e \u0442\u043e\u043b\u044c\u043a\u043e &#8216;response&#8217;. \u0422\u0430\u043a \u0432\u043e\u0442, \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0448\u0438\u0431\u043e\u0447\u043d\u044b\u0439 \ud83d\ude42 <\/p>\n<p>  \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u0435\u0449\u0435 \u044d\u0442\u043e: &quot;# TODO: \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c access_token&quot;. \u0411\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u044c access_token.py \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">access_token<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"> # *  coding: utf8 * from datetime import datetime, timedelta from django.conf import settings from django.shortcuts import redirect from downloader.vkapi import access_token_get   class AccessTokenMiddleware(object):      def process_request(self, request):                  if request.session.get('vkapi'):             data = request.session['vkapi']             expired = data['date']  timedelta(seconds=int(data['expires_in']))             if (expired  datetime.now()).seconds &lt; 3600:                 return redirect('vk_authorize')                  return None <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u041d\u043e \u0442\u0443\u0442, \u0432\u0438\u0434\u0438\u043c\u043e, \u044f \u043f\u0440\u043e\u0442\u0443\u043f\u0438\u043b \u0438 \u043e\u043f\u0438\u0441\u0430\u043b process_request \u0432\u043c\u0435\u0441\u0442\u043e process_response \u0438 \u043c\u0435\u043d\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u043b\u043e \u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e. \u041d\u0435 \u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044e \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u044c \u0431\u044b\u043b\u0430 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 (\u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0437\u0430 \u0447\u0430\u0441 \u0434\u043e \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043e\u043d \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0441\u0440\u043e\u0447\u0435\u043d\u043d\u044b\u043c, \u0441\u0447\u0438\u0442\u0430\u044e \u043d\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b\u043c).<\/p>\n<p>  \u041f\u043e\u0447\u0435\u043c\u0443 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440? \u041d\u0443 \u0442\u0443\u0442 \u044d\u0442\u043e\u2026 \u043f\u0440\u043e process_response \u043f\u043e\u0434\u0443\u043c\u0430\u043b\u043e\u0441\u044c \u0430\u0436 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0434\u0435\u043d\u044c, \u0430 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u044b\u0432\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">authorize_require decorator<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def authorize_require(view_func):          def check_session(request, *args, **kwargs):         if request.session.get('vkapi'):             data = request.session['vkapi']             expired = data['date']  timedelta(seconds=int(data['expires_in']))             if (expired - datetime.now()).seconds &lt; 3600:                 return redirect('vk_authorize')         else:             return redirect('vk_authorize')         return view_func(request, *args, **kwargs)      return check_session <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 (\u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043d\u0430\u0447\u0430\u043b\u0435 \u0444\u0443\u043d-\u0446\u0438\u0438 \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0441\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440). \u0415\u0449\u0435 \u043f\u043e\u0437\u0436\u0435 \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0430\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f (\u043d\u0435 \u0437\u043d\u0430\u044e \u0437\u0430\u0447\u0435\u043c).  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f (\u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435)<\/b><\/p>\n<div class=\"spoiler_text\">\u041e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0442\u0430\u043a\u0443\u044e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 \u043f\u0438\u0448\u0443 \u0434\u043b\u044f \u0441\u0435\u0431\u044f. \u0411\u044b\u0441\u0442\u0440\u043e \u0438 \u0434\u0435\u0448\u0435\u0432\u043e, \u0434\u0430 \u0438 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439.<\/p>\n<p>  \u0412 urls.py \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e \u0441\u0442\u0440\u043e\u043a\u0443:  <\/p>\n<pre><code class=\"python\">url(r'^registration\/$', 'downloader.views.registration', name='registration'), <\/code><\/pre>\n<p>views.py \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0432\u044c\u044e\u0445\u043e\u0439:  <\/p>\n<pre><code class=\"python\">@render_to(&quot;registration\/registration.html&quot;) def registration(request):          form = RegistrationForm()          if request.method == &quot;POST&quot;:         form = RegistrationForm(data=request.POST)         if form.is_valid():             user = User(_db=request.db,                         is_active=True,                         is_superuser=False,                         type='user',                         permissions=[],                         groups=[], )             username = form.cleaned_data['username']             password = form.cleaned_data['password']             user.update({&quot;username&quot;: username, 'password': make_password(password)})             user.create('u_%s' % slugify(username))                          auth_user = authenticate(username=username, password=password)             login(request, auth_user)             return redirect('main')                  return {         &quot;form&quot;: form     } <\/code><\/pre>\n<p>\u0412\u044c\u044e\u0445\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 CouchDB \u0438 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u0443\u0435\u0442, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043a\u0438\u0434\u0430\u0435\u0442 \u043d\u0430 1 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<p>  \u0424\u043e\u0440\u043c\u0430 RegistrationForm \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u043e\u0442 \u0442\u0430\u043a:<br \/>  forms.py  <\/p>\n<pre><code class=\"python\">class RegistrationForm(forms.Form):          username = forms.EmailField(label=_('Username'), max_length=30)     password = forms.CharField(widget=forms.PasswordInput(), label=_('Password'))      def clean_username(self):         username = self.cleaned_data['username']         user = django_couch.db().view('auth\/auth', key=username).rows         if user:             raise forms.ValidationError(_(&quot;Username already in use&quot;))         return username <\/code><\/pre>\n<p>registration\/registration.html  <\/p>\n<pre><code class=\"python\">{% extends &quot;base.html&quot; %} {% load i18n %} {% load bootstrap_toolkit %}  {% block title %}  - {% trans &quot;Registration&quot; %} {% endblock %}  {% block lib %}     &lt;link rel=&quot;stylesheet&quot; href=&quot;\/media\/css\/authentification.css&quot; \/&gt; {% endblock %}   {% block body %} &lt;div class=&quot;container&quot;&gt;     &lt;div id=&quot;register-form&quot;&gt;         &lt;form action=&quot;&quot; method=&quot;post&quot; class=&quot;form-horizontal&quot;&gt;             &lt;legend&gt;                 &lt;h2&gt;{% trans 'Registration' %}&lt;\/h2&gt;             &lt;\/legend&gt;             {{ form|as_bootstrap }}{% csrf_token %}             &lt;div class=&quot;form-actions&quot;&gt;                 &lt;button class=&quot;btn btn-primary&quot; type=&quot;submit&quot;&gt;{% trans 'Register' %}&lt;\/button&gt;&nbsp;&nbsp;                 &lt;small&gt;                     &lt;a href=&quot;{% url login %}&quot;&gt; {% trans 'Login' %}&lt;\/a&gt;                 &lt;\/small&gt;             &lt;\/div&gt;         &lt;\/form&gt;     &lt;\/div&gt; &lt;\/div&gt; {% endblock %} <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0421\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435<\/h4>\n<p>  <b>\u042d\u0442\u0430\u043f \u21163.<\/b> \u0418\u0442\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0438\u0445 \u0441\u043a\u0430\u0447\u0430\u0442\u044c. \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438\u0441\u044c \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u0431\u043e\u0442\u043e\u043c \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u0438 \u0441\u043a\u0430\u0447\u0430\u0442\u044c, \u043d\u043e \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043b\u0438\u0431\u043e \u043f\u0430\u043f\u043a\u0443 \u0441 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438, \u043b\u0438\u0431\u043e \u0430\u0440\u0445\u0438\u0432 (\u0447\u0442\u043e \u0431\u044b \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0440\u0430\u0437\u0443).  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044f (\u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435)<\/b><\/p>\n<div class=\"spoiler_text\">\u041e\u0441\u0435\u043d\u0438\u043b\u043e \u043c\u0435\u043d\u044f \u0432 \u043e\u0431\u0449\u0435\u043c\u2026 \u0435\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0435\u0442 over100500 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0442\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0433\u043d\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0435 \u0438 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e.<\/p>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f audio_get \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u0430\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0434\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430, \u0447\u0442\u043e \u0434\u0430\u043b\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e:  <\/p>\n<pre><code class=\"python\">def audio_get(session, album_id='', offset=0, count=100):          params = {         'owner_id': session['user_id'],         'offset': offset,         'count': count,         'album_id': album_id,     }     return request_api('audio.get', session['access_token'], params) <\/code><\/pre>\n<p>vk_audios \u0432 \u0444\u0430\u0439\u043b\u0435 view.py \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434:  <\/p>\n<pre><code class=\"python\">@authorize_require @render_to(&quot;downloader\/vk_audios.html&quot;) def vk_audios(request, album_id=''):            try:         page = int(request.GET.get('page', 1))     except:         raise Http404(&quot;Error page param: %s&quot; % request.GET['page'])          offset = 100 * (int(page) - 1)          response = audio_get(request.session['vkapi'], album_id=album_id, offset=offset)          audios = response.get('items', [])     audios_count = response.get('count')           return {         'album_id': album_id,         'audios_count': audios_count,         'page': page,         'offset': offset,         'audios': audios,      } <\/code><\/pre>\n<p>\u0411\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d inclusion_tag, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 id \u0430\u043b\u044c\u0431\u043e\u043c\u0430, \u0447\u0442\u043e \u0431\u044b \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.  <\/p>\n<pre><code class=\"python\">@register.inclusion_tag('snippets\/pagination.html') def render_pagination(audios_count, page, album_id=False):          pages_count = int(math.ceil(audios_count \/ 100.0))  1          pages = range(1, pages_count)          return {         &quot;pages&quot;: pages,         &quot;page&quot;: page,         &quot;album_id&quot;: album_id,     } <\/code><\/pre>\n<p>\u0418 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d html-\u0444\u0430\u0439\u043b (snippets\/pagination.html):  <\/p>\n<pre><code class=\"html\">{% load i18n %}  {% if pages|length &gt; 1 %} &lt;div class=&quot;pagination pagination-right&quot;&gt;     &lt;ul&gt;     {% for p in pages %}         &lt;li {% ifequal p page %}class=&quot;active&quot;{% endifequal %}&gt;             {% if album_id %}             &lt;a href=&quot;{% url vk_audios album_id %}?page={{ p }}&quot;&gt;{{ p }}&lt;\/a&gt;             {% else %}             &lt;a href=&quot;{% url vk_audios %}?page={{ p }}&quot;&gt;{{ p }}&lt;\/a&gt;             {% endif %}         &lt;\/li&gt;     {% endfor %}     &lt;\/ul&gt; &lt;\/div&gt; {% endif %} <\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e \u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u043b \u0441\u0435\u0431\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e 100 \u0444\u0430\u0439\u043b\u043e\u0432. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0438\u0445 \u0441\u043a\u0430\u0447\u0430\u0442\u044c.  <\/div>\n<\/div>\n<p>  \u041d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b\u2026 \u043d\u043e \u043a\u0430\u043a? \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u0436\u0434\u0435\u0442, \u043f\u043e\u043a\u0430 \u0435\u043c\u0443 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0434\u0430\u0441\u0442 \u0430\u0440\u0445\u0438\u0432? \u0425\u043c\u2026 \u0420\u0435\u0448\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u043f\u0440\u0438\u043d\u044f\u043b\u0441\u044f \u0442\u0430\u043a:<br \/>  <b>\u042d\u0442\u0430\u043f \u21163.1 \u2014 \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435.<\/b> \u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0441 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432\u044b\u0432\u0435\u043b \u0444\u043e\u0440\u043c\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0443\u0436\u043d\u043e \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 email \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435. <\/p>\n<p>  form.py \u041f\u043e\u043f\u043e\u043b\u043d\u0438\u043b\u0441\u044f \u043d\u043e\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">forms.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">class RequestsForm(forms.Form):          username = forms.EmailField(label=_('E-mail'),                                 help_text=_(&quot;Archive with audios will be send to this email&quot;)) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043f\u043e\u043b\u0435 username? \u0412\u0441\u0435 \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 email. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441 username = email, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u043e\u0448\u0435\u043b \u043d\u0430 \u0441\u0430\u0439\u0442, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e email, \u0430 \u043e\u043d \u0435\u0441\u043b\u0438 \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0442\u044b\u043a\u0430\u0435\u0442 \u0432 \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043b\u043e\u0436\u0438\u043c \u0435\u0433\u043e id \u0432 nsq:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0432 couchdb<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>* _id - r_&lt;hash&gt; * status - new * username - test@test.com * is_active - true * audios - [    {        &quot;url&quot;: &quot;&lt;url&gt;&quot;,        &quot;processed&quot;: true,        &quot;title&quot;: &quot;Three Days Grace - I Hate Everything About You&quot;    } ] * date_created - 2013-10-20 11:27:21.208492 * type - request <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u041f\u043e\u043b\u0435 status \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439: \u00abprocessing\u00bb, \u00aberror\u00bb, \u00abprocessed\u00bb, \u00abdeleted\u00bb. <\/p>\n<p>  \u0414\u043b\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 couch&#8217;a \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0430:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">class DownloadRequest(django_couch.Document):          def __init__(self, *args, **kwargs):         self._db = django_couch.db('db_requests')         self.type = 'request'         self.is_active = True         self.status = 'new'         self.date_created = datetime.now().isoformat(' ')         super(DownloadRequest, self).__init__(*args, **kwargs)              @staticmethod     def load(resp_id):         db = django_couch.db('db_requests')                  if resp_id in db:             doc = DownloadRequest(db[resp_id])             assert doc.type == 'request', _(&quot;Invalid data loaded&quot;)                          return doc                      else:             raise Http404(_(&quot;Can't find download request with id '%s'&quot;) % id)              @staticmethod     def get_list(email):         pass <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0427\u0442\u043e \u0431\u044b \u043b\u043e\u0436\u0438\u0442\u044c \u0432 nsq \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0441 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0435\u0441\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">nsq_push<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def nsq_push(topic, message, fmt='json'):     url = &quot;http:\/\/%s\/put?topic=%s&quot; % (random.choice(settings.NSQD_HTTP_ADDRESSES), topic)          if fmt == 'json':         message_encoded = json.dumps(message)     elif fmt == 'raw':         message_encoded = message     else:         raise Exception(&quot;Unsupported message encode format: %s&quot; % fmt)          r = requests.post(url, data=message_encoded)          return r.ok <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0410 \u0432\u044c\u044e\u0445\u0430 vk_audios \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">vk_audios<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">@authorize_require @render_to(&quot;downloader\/vk_audios.html&quot;) def vk_audios(request, album_id=''):          try:         page = int(request.GET.get('page', 1))     except:         page = 1         messages.error(request, _(&quot;Error page: %s. Changed to 1&quot;) % request.GET.get('page'))          offset = 100 * (int(page) - 1)          response = audio_get(request.session['vkapi'], album_id=album_id, offset=offset)          audios = response.get('items', [])     audios_count = response.get('count')          if request.user.is_authenticated():         initial_data = request.user     else:         initial_data = {'username': ''}          form = RequestsForm(request.POST or None, initial=initial_data)          if form.is_valid():         request_doc = DownloadRequest()         request_doc.update(form.cleaned_data)                  formated_audios = []         for audio in audios:             formated_data = {                 'title': &quot;%s - %s&quot; % (audio['artist'], audio['title']),                 'url': audio['url'],                 'processed': False,             }             formated_audios.append(formated_data)                  request_doc.update({'audios': formated_audios})         request_doc.create('r', force_random_suffix=True)         messages.success(request, _(&quot;Download request successfully created&quot;))         nsq_push('download_requests', request_doc.id, fmt=&quot;raw&quot;)              return {         'album_id': album_id,         'audios_count': audios_count,         'page': page,         'offset': offset,         'audios': audios,         'form': form,     } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0438 \u043b\u043e\u0436\u0438\u043c id \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0432 nsq. <b>\u041d\u041e<\/b>, \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0432\u043e\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0438\u0445 \u0441\u0442\u0430\u0442\u0443\u0441\u044b\u2026   <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0412\u044b\u0432\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435):<\/b><\/p>\n<div class=\"spoiler_text\">\u0418 \u043f\u0440\u0438\u043d\u044f\u043b\u0441\u044f \u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044c\u044e\u0445\u0443 \u0434\u043b\u044f \u0438\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0411\u044b\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0442\u0430\u0436\u0435 \u0444\u043e\u0440\u043c\u0430, \u0447\u0442\u043e \u0438 \u0432\u044b\u0448\u0435, \u0434\u043b\u044f \u043e\u0442\u0431\u043e\u0440\u0430 \u043f\u043e email&#8217;\u0443. \u0412 CouchDB \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u0438\u0437\u0430\u0439\u043d \u0434\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u0440\u043e\u0438\u0442 \u0438\u043d\u0434\u0435\u043a\u0441 \u0441 \u043a\u043b\u044e\u0447\u0435\u043c [email, \u0434\u0430\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f]:  <\/p>\n<pre><code class=\"javascript\">function(doc) {     if (doc.type == 'request' && doc.is_active) {         emit([doc.username, doc.date_created])     } } <\/code><\/pre>\n<p>\u0410 \u0432 \u0430\u043f\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u044c\u044e\u0445\u0430 requests_list:  <\/p>\n<pre><code class=\"python\">@render_to(&quot;downloader\/requests.html&quot;) def requests_list(request):          requests = []          if request.user.is_authenticated():         initial_data = request.user     else:         initial_data = {'username': ''}          form = RequestsForm(request.GET or None, initial=initial_data)          if form.is_valid():         requests = DownloadRequest.get_list(form.cleaned_data['username'])          return {         'form': form,         'requests': requests,     } <\/code><\/pre>\n<p>\u0418 \u0434\u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f get_list \u0432 \u043c\u043e\u0434\u0435\u043b\u044c DownloadRequest:  <\/p>\n<pre><code class=\"python\">@staticmethod def get_list(email):     db = django_couch.db('db_requests')          requests = db.view('requests\/list', include_docs=True, startkey=[email], endkey=[email, {}]).rows     return [DownloadRequest(request) for request in requests] <\/code><\/pre>\n<p>\u0425\u044d\u0445! \u0422\u0435\u043f\u0435\u0440\u044c \u044f \u0435\u0449\u0435 \u0432\u0438\u0436\u0443 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c nsq-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c&#8230;<\/p><\/div>\n<\/div>\n<p>  <b>\u042d\u0442\u0430\u043f \u21163.2 \u2014 \u0421\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435.<\/b> \u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430\u0431\u0440\u043e\u0441\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 nsq:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">management\/commands\/download_request_worker.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">#!\/usr\/bin\/env python # -*- coding: utf-8 -*- import os import sys import nsq import signal import requests import django_couch  from django.conf import settings from django.core.management.base import BaseCommand from logger import logger  from downloader.models import DownloadRequest           class Command(BaseCommand):          def handle(self, *args, **options):                  self.log = logger('download_request', int(options['verbosity']) &gt; 1, settings.LOG_DIR)                  signal.signal(signal.SIGINT, self.signal_callback)         signal.signal(signal.SIGTERM, self.signal_callback)                  self.db = django_couch.db('db_requests')                  nsq.Reader({&quot;message_callback&quot;: self.message_callback},                    &quot;download_requests&quot;,                    &quot;download_requests&quot;,                    nsqd_tcp_addresses=settings.NSQD_TCP_ADDRESSES)         self.log.debug(&quot;Starting NSQ...&quot;)         nsq.run()              def process_request(self, request):         self.log.debug(&quot;Setting status '%s' to 'processing.'&quot; % request.status)                  request.status = 'processing'         request.save()                  user_path = os.path.join(settings.DOWNLOAD_AUDIOS_DIR, request.username)         if not os.path.exists(user_path):             os.mkdir(user_path)                  self.log.debug(&quot;User dir: %s&quot; % user_path)                      request_path = os.path.join(user_path, request.id)         if not os.path.exists(request_path):             os.mkdir(request_path)                  self.log.debug(&quot;Download request dir: %s&quot; % request_path)                  for audio in request.audios:             self.log.debug(&quot;Title: %s. Url: %s&quot;, audio['title'], audio['url'])             if audio.get('processed', False):                 self.log.debug(&quot;Already processed&quot;)                 continue                          self.log.debug(&quot;Downloading file..&quot;)             response = requests.get(audio['url'])             self.log.debug(&quot;Downloaded&quot;)                          filename = os.path.join(request_path, &quot;%s.mp3&quot; % audio['title'])             self.log.debug(&quot;Writing to filename: %s&quot; % filename)                          with open(filename, 'wb') as f:                 f.write(response.content)             self.log.debug(&quot;Setting audio to processed&quot;)             audio['processed'] = True                  request.save()      def message_callback(self, message):         self.log.debug(&quot;Processing message id: %s&quot;, message.id)                  self.log.debug(&quot;Message data: %s&quot;, message.body)                  try:             request = DownloadRequest.load(message.body)             self.log.info(&quot;Document loaded. Audios count: %s&quot; % len(request.audios))             self.process_request(request)             self.log.debug(&quot;Setting status '%s' to 'processed.'&quot; % request.status)             request.status = 'processed'             request.save()             self.log.debug(&quot;Request successfullly processed.&quot;)         except:             return False         return True      def signal_callback(self, signal_number, stack_frame):         self.log.critical(&quot;Signal %d received. Shutting down&quot;, signal_number)                  sys.exit(-1) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>\u0418\u0442\u0430\u043a \u0447\u0442\u043e \u043e\u043d \u0443\u043c\u0435\u043b:<br \/>   \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u043b id \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u0438<br \/>   \u2014 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b \u043f\u0430\u043f\u043a\u0443, \u0435\u0441\u043b\u0438 \u0435\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e<br \/>   \u2014 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043b \u0442\u0443\u0434\u0430 \u0430\u0443\u0434\u0438\u043e\u0444\u0430\u0439\u043b\u044b<\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0435\u0449\u0435 \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 email&#8217;a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e. \u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u0432 nsq \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f, \u0438\u0431\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0431\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c url \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435, \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c host, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 django \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f request.get_host(), \u043d\u043e \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a request&#8217;\u0443 \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043a\u0442\u043e \u0437\u043d\u0430\u0435\u0442 \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435), \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043b\u043e\u0436\u0438\u0442\u044c \u0432 nsq \u043c\u0435\u0441\u0435\u0434\u0436 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430: {&#8216;host&#8217;: request.get_host(), &#8216;id&#8217;: &lt;id \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435&gt;}.<\/p>\n<p>  \u041d\u043e \u0432\u0441\u0435 \u0435\u0449\u0435 \u044d\u0442\u043e \u0431\u044b\u043b\u0438 \u043d\u0430\u0431\u0440\u043e\u0441\u043a\u0438. \u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u0442\u043e\u043c\u0443 \u2014 nsq. \u0423 nsq \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439:<br \/>   \u2014 \u043a\u0430\u0436\u0434\u044b\u0445 N \u0441\u0435\u043a\u0443\u043d\u0434 \u043e\u043d \u0448\u043b\u0435\u0442 heartbeat \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u0432\u043e\u0440\u043a\u0435\u0440\u0430\u043c \u0438 \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442 2 \u0440\u0430\u0437\u0430, \u043a\u043e\u043d\u043d\u0435\u043a\u0442 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f. \u0422.\u0435. \u0435\u0441\u043b\u0438 \u043d\u0430\u0448 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u043e\u0432, \u043a\u043e\u043d\u043d\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442\u044c.<br \/>   \u2014 \u0435\u0441\u043b\u0438 nsq \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0438 N \u0441\u0435\u043a\u0443\u043d\u0434, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442\u0434\u0430\u0435\u0442\u0441\u044f \u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443. \u0422.\u0435. \u0435\u0441\u043b\u0438 \u044f \u0437\u0430\u043f\u0443\u0449\u0443 2 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0442\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u043d\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c 2 \u0440\u0430\u0437\u0430.<\/p>\n<p>  \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u0432 pynsq \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c async mode \u0438 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u0445. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u0445\u043e\u0440\u043e\u0448\u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0438 \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u043a\u043e\u0434 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f.<\/p>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 nsq-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">management\/commands\/download_request_worker.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">#!\/usr\/bin\/env python # -*- coding: utf-8 -*- import os import sys import nsq import json import time import shutil import signal import requests import django_couch import multiprocessing  from logger import logger from datetime import datetime  from django.conf import settings from django.core.mail import send_mail from django.core.urlresolvers import reverse from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from django.core.management.base import BaseCommand  from downloader.models import DownloadRequest from downloader.views import nsq_push   class DownloadRequestProcess(multiprocessing.Process):          def __init__(self, log, message, *args, **kwargs):         self.log = log         self.message = message         super(DownloadRequestProcess, self).__init__(*args, **kwargs)              def process_request(self, drequest):         self.log.debug(&quot;Setting status '%s' to 'processing'. For doc: %s&quot; % (drequest.status, drequest.id))                  drequest.status = 'processing'         drequest.save()                      request_path = os.path.join(settings.DOWNLOAD_AUDIOS_DIR, drequest.id)         if not os.path.exists(request_path):             os.mkdir(request_path)                  self.log.debug(&quot;Download request dir: %s&quot; % request_path)                  for audio in drequest.audios:             self.log.debug(&quot;Title: %s. Url: %s&quot;, audio['title'], audio['url'])             if audio.get('processed', False):                 self.log.debug(&quot;Audio already processed&quot;)                 continue                          filename = os.path.join(request_path, &quot;%s.mp3&quot; % audio['title'])             self.log.debug(&quot;Filename: %s&quot; % filename)                          self.log.debug(&quot;Downloading file...&quot;)             response = requests.get(audio['url'])             self.log.debug(&quot;Downloaded&quot;)                          with open(filename, 'wb') as f:                 f.write(response.content)             self.log.debug(&quot;Setting audio to processed&quot;)             audio['processed'] = True                  archive_path = None         if drequest.get('archive'):             archive_path = os.path.exists(os.path.join(request_path, drequest.archive))                  if not drequest.get('archive') and not archive_path:             self.log.debug(&quot;Writing archive&quot;)             archive = shutil.make_archive(request_path, 'gztar', settings.DOWNLOAD_AUDIOS_DIR, drequest.id)             self.log.debug(&quot;Archive: %s&quot; % archive)             drequest['archive'] = os.path.basename(archive)                  self.log.debug(&quot;Deleting download path dir&quot;)         shutil.rmtree(request_path)                  self.log.debug(&quot;Setting status '%s' to 'processed.'&quot; % drequest.status)         drequest['date_processed'] = datetime.now().isoformat(' ')         drequest.status = 'processed'         drequest.save()              def run(self):         self.log.debug(&quot;Message data: %s&quot;, self.message.body)                  data = json.loads(self.message.body)                  attempts = data.get('attempts', 1)         if (attempts &gt; 5):             self.log.debug(&quot;Attempts limit reached, dropping this request&quot;)             return                  drequest = DownloadRequest.load(data['id'])         self.log.info(&quot;Document loaded. Audios count: %s&quot; % len(drequest.audios))                  if drequest.get('processed'):             self.log.debug(&quot;Download request already processed&quot;)             return                  try:             self.process_request(drequest)             self.log.debug(&quot;Download request successfullly processed. Sending mail.&quot;)                          if drequest.get('archive'):                 archive_link = 'http:\/\/%s%s' % (data['host'], reverse('archive_link', args=[drequest.archive]))                 self.log.debug(&quot;Link to archive: %s&quot; % archive_link)                 send_mail(_(&quot;Take you archive&quot;),                           render_to_string(&quot;mail\/archive_mail.html&quot;, {'archive_link': archive_link}),                           settings.SERVER_EMAIL,                           [drequest.username])                 self.log.debug(&quot;Mail sent&quot;)         except:             self.log.debug(&quot;Error occured: %s. Setting status to error&quot; % sys.exc_info()[1])             drequest.status = 'error'             drequest.status_verbose = &quot;%s&quot; % sys.exc_info()[1]             drequest.save()                          sleep_time = 30 * attempts             self.log.debug(&quot;Pushing it back to nsq in %s seconds. Topic: download_requests&quot; % sleep_time)             time.sleep(sleep_time)             nsq_push('download_requests', {&quot;host&quot;: data['host'], 'id': drequest.id, 'attempts': attempts + 1})               class Command(BaseCommand):          def handle(self, *args, **options):                  self.log = logger('download_request', int(options['verbosity']) &gt; 1, settings.LOG_DIR)                  signal.signal(signal.SIGINT, self.signal_callback)         signal.signal(signal.SIGTERM, self.signal_callback)                  self.db = django_couch.db('db_requests')                  nsq.Reader({&quot;message_callback&quot;: self.message_callback},                    &quot;download_requests&quot;,                    &quot;download_requests&quot;,                    nsqd_tcp_addresses=settings.NSQD_TCP_ADDRESSES)         self.log.debug(&quot;Starting NSQ...&quot;)         self.processes = []         nsq.run()          def message_callback(self, message):         self.log.debug(&quot;Processing message id: %s&quot;, message.id)                  message.enable_async()                  process = DownloadRequestProcess(self.log, message)         process.start()                  self.log.debug(&quot;Process: %s&quot;, process)         message.finish()                  self.processes.append(process)      def signal_callback(self, signal_number, stack_frame):         self.log.critical(&quot;Signal %d received. Shutting down&quot;, signal_number)                  for process in self.processes:             if process.is_alive():                 process.join()                 process.terminate()                  sys.exit(-1) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0418\u0442\u0430\u043a \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a:<br \/>   \u2014 \u043b\u043e\u0432\u0438\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 nsq<br \/>   \u2014 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441<br \/>   \u2014 \u043e\u0442\u043c\u0435\u0447\u0430\u0435\u0442 nsq-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0435<br \/>   \u2014 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0440\u0445\u0438\u0432<br \/>   \u2014 \u043e\u0442\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f emal<br \/>   \u2014 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u043b\u043e\u0436\u0438\u0442\u044c \u044d\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 nsq \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u044b\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043e\u043a. \u0417\u0430 6 \u0440\u0430\u0437\u043e\u043c \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0435\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0443\u0442\u0438 \u2014 \u043d\u0435 \u0438\u0441\u043a\u0430\u043b, \u0445\u0432\u0430\u0442\u0438\u043b\u043e \u044d\u0442\u043e\u0433\u043e).<\/p>\n<p>  \u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 nsq \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434: {&#8216;host&#8217;: , &#8216;id&#8217;: &lt;id \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435&gt;, &#8216;attempts&#8217;: &lt;\u2116 \u043f\u043e\u043f\u044b\u0442\u043a\u0438&gt;}). \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043b\u043e\u0436\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438. \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u043b \u0435\u0435 \u043f\u043e \u0444\u043e\u0440\u043c\u0443\u043b\u0435 30 \u0441\u0435\u043a \u0443\u043c\u043d\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043d\u0430 \u2116 \u043f\u043e\u043f\u044b\u0442\u043a\u0438.<\/p>\n<h4>\u041a\u043e\u043d\u0435\u0446<\/h4>\n<p>  \u042f \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u043b \u0432\u0441\u0435 \u0441\u0432\u043e\u0438 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0438. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432, \u0447\u0442\u043e \u0430\u0440\u0445\u0438\u0432 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0432\u0435\u0441\u0438\u0442 650\u041c\u0431 \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u0411\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0435\u0449\u0435 \u043e\u0434\u043d\u0430 \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0432\u0441\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0430\u0440\u0445\u0438\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \u043d\u0430 \u00abdeleted\u00bb. \u0422\u043e\u0436\u0435 \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u0438\u0437\u044f\u0449\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c \ud83d\ude42  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">management\/commands\/remove_in_24.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">#!\/usr\/bin\/env python # -*- coding: utf-8 -*- import os import django_couch from datetime import datetime, timedelta  from logger import logger  from django.conf import settings from django.core.management.base import BaseCommand   class Command(BaseCommand):      help = u'prepare and send fax document'          def handle(self, *args, **options):                  self.log = logger('delete_in_24', int(options['verbosity']) &gt; 1, settings.LOG_DIR)         self.db = django_couch.db(&quot;db_requests&quot;)                  requests = self.db.view(&quot;request_processed\/list&quot;, include_docs=True).rows         self.log.debug(&quot;Founded %s processed download requests&quot;, len(requests))         for req in requests:             self.log.debug(&quot;%s&quot;, req.value)             self.log.debug(&quot;ID: %s. Archive: %s&quot;, req.id, req.value)                          now = datetime.now()             date_expired = datetime.strptime(req.key, settings.DATETIME_FMT) + timedelta(hours=24)             self.log.debug(&quot;Now: %s. Expired: %s&quot;, now.strftime(settings.DATETIME_FMT), date_expired.strftime(settings.DATETIME_FMT))                          if now &lt; date_expired:                 self.log.debug(&quot;Passing this doc&quot;)                 continue                           archive_path = os.path.join(settings.DOWNLOAD_AUDIOS_DIR, req.value)             self.log.debug(&quot;Archive path: %s&quot;, archive_path)                            if os.path.exists(archive_path):                 self.log.debug(&quot;Deleting file: %s&quot;, archive_path)                 os.unlink(archive_path)             else:                 self.log.warning(&quot;Path doesn't exists&quot;)                            doc = req.doc             self.log.debug(&quot;Settings status '%s' to 'deleted'&quot;, doc.status)             doc.status = 'deleted'             doc.save(self.db) <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  Couchdb \u0434\u0438\u0437\u0430\u0439\u043d \u0434\u043e\u043a request_processed\/list, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0438  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">request_processed\/list<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function(doc) {     if (doc.type == 'request' && doc.archive     && doc.date_processed && doc.status != 'deleted') {         emit(doc.date_processed.slice(0, 19), doc.archive);     } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 bitbucket: <a href=\"https:\/\/bitbucket.org\/Kolyanu4\/vkdownloader\/src\">bitbucket.org\/Kolyanu4\/vkdownloader\/src<\/a> \t\t\t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/198258\/\"> http:\/\/habrahabr.ru\/post\/198258\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">\n<h4>\u041f\u0440\u0435\u0434\u0438\u0441\u0442\u043e\u0440\u0438\u044f<\/h4>\n<p>  \u041a\u0430\u0436\u0434\u043e\u0435 \u0443\u0442\u0440\u043e \u044f \u0435\u0437\u0436\u0443 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0438 \u044d\u0442\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 <s>N-\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/s> \u043e\u0442 15 \u043c\u0438\u043d\u0443\u0442 (\u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0435) \u0434\u043e 40 \u043c\u0438\u043d\u0443\u0442 (\u043d\u0430 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0435). \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0443\u0442\u0440\u043e\u043c \u043f\u043e \u0440\u0430\u0434\u0438\u043e \u043a\u0440\u0443\u0442\u044f\u0442 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043c\u0443\u0437\u044b\u043a\u0443, \u0430 \u0440\u0430\u0437\u043d\u044b\u0435 \u00ab\u0440\u0430\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435\u00bb \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u041e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u044f \u0435\u0437\u0434\u0438\u043b \u043b\u0438\u0431\u043e \u0441 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u043c\u0430\u0433\u043d\u0438\u0442\u043e\u0444\u043e\u043d\u043e\u043c, \u043b\u0438\u0431\u043e \u0432\u0441\u044e \u0434\u043e\u0440\u043e\u0433\u0443 \u0438\u0441\u043a\u0430\u043b \u0440\u0430\u0434\u0438\u043e\u0441\u0442\u0430\u043d\u0446\u0438\u044e, \u043b\u0438\u0431\u043e \u0432\u0440\u0443\u0431\u0430\u043b \u043d\u0430\u0443\u0448\u043d\u0438\u043a\u0438 (\u043f\u043e\u043a\u0430 \u043d\u0435 \u0440\u0430\u0437\u0434\u0430\u0432\u0438\u043b \u0441\u0432\u043e\u0439 \u0442\u0435\u043b\u0435\u0444\u043e\u043d).<\/p>\n<p>  \u0418 \u0432\u043e\u0442 \u043c\u043d\u0435 \u044d\u0442\u043e \u043d\u0430\u0434\u043e\u0435\u043b\u043e. \u041c\u0430\u0433\u043d\u0438\u0442\u043e\u043b\u0430 \u0443 \u043c\u0435\u043d\u044f \u0438\u0437 \u0434\u0435\u0448\u0435\u0432\u044b\u0445, \u043d\u043e \u0443\u043c\u0435\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0441 \u0444\u043b\u0435\u0448\u0435\u043a. \u0412 \u043e\u0434\u0438\u043d \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0434\u0435\u043d\u044c, \u043f\u043e \u0434\u043e\u0440\u043e\u0433\u0435 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443, \u044f \u0432\u0437\u044f\u043b \u0438 \u043a\u0443\u043f\u0438\u043b SD-\u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0443 (\u0443\u0434\u043e\u0431\u043d\u0435\u0439 \u0432\u0441\u0435\u0433\u043e \u0438\u0431\u043e \u043d\u0435 \u0432\u044b\u043f\u0438\u0440\u0430\u0435\u0442). \u0412\u0441\u0435 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u043f\u0440\u043e\u0441 \u0441\u0442\u0430\u043b \u0438\u043d\u0430\u0447\u0435: \u00ab\u0413\u0434\u0435 \u0432\u0437\u044f\u0442\u044c \u043c\u0443\u0437\u044b\u043a\u0443?\u00bb. \u041d\u0435 \u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043c\u043d\u0435 \u0445\u0432\u0430\u0442\u0438\u0442 \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\u0430 \u0441 VK. \u0412\u0441\u0435\u0433\u043e-\u0442\u043e 400+ \u043f\u0435\u0441\u0435\u043d, \u043d\u043e \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043a\u0430\u0447\u0430\u0442\u044c.  <\/p>\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-198258","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/198258","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=198258"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/198258\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=198258"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=198258"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=198258"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}