diff --git a/2420/3/Gemfile b/2420/3/Gemfile
new file mode 100644
index 000000000..968f3cd7f
--- /dev/null
+++ b/2420/3/Gemfile
@@ -0,0 +1,8 @@
+source 'http://rubygems.org'
+
+gem 'capybara'
+gem 'ohm'
+gem 'redis'
+gem 'selenium-webdriver'
+gem 'shotgun'
+gem 'sinatra'
diff --git a/2420/3/Gemfile.lock b/2420/3/Gemfile.lock
new file mode 100644
index 000000000..1fe315047
--- /dev/null
+++ b/2420/3/Gemfile.lock
@@ -0,0 +1,66 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ addressable (2.5.2)
+ public_suffix (>= 2.0.2, < 4.0)
+ capybara (3.4.1)
+ addressable
+ mini_mime (>= 0.1.3)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ xpath (~> 3.1)
+ childprocess (0.9.0)
+ ffi (~> 1.0, >= 1.0.11)
+ ffi (1.9.25)
+ hiredis (0.6.1)
+ mini_mime (1.0.0)
+ mini_portile2 (2.3.0)
+ mustermann (1.0.2)
+ nest (3.1.1)
+ redic
+ nokogiri (1.8.4)
+ mini_portile2 (~> 2.3.0)
+ ohm (3.1.1)
+ nest (~> 3)
+ redic (~> 1.5.0)
+ stal
+ public_suffix (3.0.2)
+ rack (2.0.5)
+ rack-protection (2.0.3)
+ rack
+ rack-test (1.1.0)
+ rack (>= 1.0, < 3)
+ redic (1.5.0)
+ hiredis
+ redis (4.0.1)
+ rubyzip (1.2.1)
+ selenium-webdriver (3.13.1)
+ childprocess (~> 0.5)
+ rubyzip (~> 1.2)
+ shotgun (0.9.2)
+ rack (>= 1.0)
+ sinatra (2.0.3)
+ mustermann (~> 1.0)
+ rack (~> 2.0)
+ rack-protection (= 2.0.3)
+ tilt (~> 2.0)
+ stal (0.3.0)
+ redic (~> 1.5)
+ tilt (2.0.8)
+ xpath (3.1.0)
+ nokogiri (~> 1.8)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ capybara
+ ohm
+ redis
+ selenium-webdriver
+ shotgun
+ sinatra
+
+BUNDLED WITH
+ 1.16.2
diff --git a/2420/3/config.ru b/2420/3/config.ru
new file mode 100644
index 000000000..cbf68412f
--- /dev/null
+++ b/2420/3/config.ru
@@ -0,0 +1,10 @@
+require 'sinatra/base'
+require 'ohm'
+
+Dir.glob('./{helpers,controllers}/*.rb').each do |file|
+ require file
+end
+
+map('/') { run ApplicationController }
+map('/table') { run TableController }
+map('/analysis') { run AnalysisController }
diff --git a/2420/3/controllers/analysis_controller.rb b/2420/3/controllers/analysis_controller.rb
new file mode 100644
index 000000000..dcb8ebce1
--- /dev/null
+++ b/2420/3/controllers/analysis_controller.rb
@@ -0,0 +1,13 @@
+# class AnalysisController
+class AnalysisController < ApplicationController
+ get '/:id' do
+ @id = params[:id]
+ @first_id = Article[@id].comments.first.id
+ @last_id = Article[@id].comments.last.id
+ erb :analysis
+ end
+
+ post '/:id' do
+ erb :analysis
+ end
+end
diff --git a/2420/3/controllers/application_controller.rb b/2420/3/controllers/application_controller.rb
new file mode 100644
index 000000000..21648e215
--- /dev/null
+++ b/2420/3/controllers/application_controller.rb
@@ -0,0 +1,14 @@
+# class ApplicationController
+class ApplicationController < Sinatra::Base
+ helpers ApplicationHelper
+
+ configure do
+ set :views, './views/'
+ set :root, File.expand_path('..', __dir__)
+ end
+
+ get '/' do
+ title 'My App'
+ erb :table
+ end
+end
diff --git a/2420/3/controllers/table_controller.rb b/2420/3/controllers/table_controller.rb
new file mode 100644
index 000000000..d01f160b9
--- /dev/null
+++ b/2420/3/controllers/table_controller.rb
@@ -0,0 +1,22 @@
+require 'ohm'
+require 'redis'
+# class TableController
+class TableController < ApplicationController
+ get '/' do
+ erb :table
+ end
+
+ post '/' do
+ scores = []
+ article = Article.create(url: params[:new_url]) unless params[:new_url].empty?
+ comments = Pars.new(params[:new_url]).comments
+ comments.each do |comment|
+ score = ManipulationCommentScore.new(Analytics.new(comment).run).run
+ scores << score
+ comment_attribute = Comment.create(body: comment, comment_rating: score)
+ article.comments.push(comment_attribute)
+ end
+ article.update article_rating: ManipulationArticleScore.new(scores).run
+ erb :table
+ end
+end
diff --git a/2420/3/helpers/application_helper.rb b/2420/3/helpers/application_helper.rb
new file mode 100644
index 000000000..54cf5e2f8
--- /dev/null
+++ b/2420/3/helpers/application_helper.rb
@@ -0,0 +1,7 @@
+# module ApplicationHelper
+module ApplicationHelper
+ def title(value = nil)
+ @title = value if value
+ @title || 'MyApp'
+ end
+end
diff --git a/2420/3/helpers/manipulation.rb b/2420/3/helpers/manipulation.rb
new file mode 100644
index 000000000..c2173d3c4
--- /dev/null
+++ b/2420/3/helpers/manipulation.rb
@@ -0,0 +1,26 @@
+# class ManipulationCommentScore
+class ManipulationCommentScore
+ attr_reader :score
+
+ def initialize(score)
+ @score = score
+ end
+
+ def run
+ result = score * 100 / 0.5 - 100 if score <= 0.5
+ result = (score - 0.5) * 100 / 0.5 if score >= 0.5
+ result.round
+ end
+end
+# class ManipulationArticleScore
+class ManipulationArticleScore
+ attr_reader :scores
+
+ def initialize(scores)
+ @scores = scores
+ end
+
+ def run
+ scores.sum / scores.size.to_i
+ end
+end
diff --git a/2420/3/helpers/models_article.rb b/2420/3/helpers/models_article.rb
new file mode 100644
index 000000000..c4a013495
--- /dev/null
+++ b/2420/3/helpers/models_article.rb
@@ -0,0 +1,12 @@
+require 'ohm'
+# class Article
+class Article < Ohm::Model
+ list :comments, :Comment
+ attribute :article_rating
+ attribute :url
+end
+# class Comment
+class Comment < Ohm::Model
+ attribute :body
+ attribute :comment_rating
+end
diff --git a/2420/3/helpers/parser.rb b/2420/3/helpers/parser.rb
new file mode 100644
index 000000000..763e00701
--- /dev/null
+++ b/2420/3/helpers/parser.rb
@@ -0,0 +1,25 @@
+require 'capybara'
+
+Capybara.register_driver :selenium do |app|
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
+end
+# :reek:FeatureEnvy
+# rubocop:disable Metrics/LineLength
+class Pars
+ attr_reader :link
+
+ def initialize(link)
+ @link = link
+ end
+
+ def comments
+ session = Capybara::Session.new(:selenium)
+ session.visit(link)
+ session.find('a.button-style.button-style_subsidiary.button-style_big.news-form__button.news-form__button_width_full.news-form__button_font-weight_semibold').click
+ session.find_by_id('comments')
+ .all('.news-comment__speech.news-comment__speech_base' || '.news-comment__unit')
+ .first(20)
+ .map(&:text)
+ end
+end
+# rubocop:enable Metrics/LineLength
diff --git a/2420/3/helpers/text_analysis.rb b/2420/3/helpers/text_analysis.rb
new file mode 100644
index 000000000..8eaf25b12
--- /dev/null
+++ b/2420/3/helpers/text_analysis.rb
@@ -0,0 +1,36 @@
+require 'net/https'
+require 'uri'
+require 'json'
+# :reek:FeatureEnvy
+# :reek:TooManyStatements
+# class Analytic
+class Analytics
+ attr_reader :text
+
+ def initialize(text)
+ @text = text
+ end
+
+ def run
+ access_key = SECRET_KEY.freeze
+
+ uri = 'https://westcentralus.api.cognitive.microsoft.com'
+ path = '/text/analytics/v2.0/sentiment'
+
+ uri = URI(uri + path)
+
+ documents = { 'documents' => [{ 'id': '1', 'language': 'ru', 'text': text }] }
+ request = Net::HTTP::Post.new(uri)
+ request['Content-Type'] = 'application/json'
+ request['Ocp-Apim-Subscription-Key'] = access_key
+ request.body = documents.to_json
+
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
+ http.request(request)
+ end
+
+ information = JSON.pretty_generate(JSON(response.body))
+ information = information.gsub(/^\s+|\n|\r|\s+$|\D/, ' ').split
+ (information[0] + '.' + information[1]).to_f
+ end
+end
diff --git a/2420/3/views/analysis.erb b/2420/3/views/analysis.erb
new file mode 100644
index 000000000..43158fc9b
--- /dev/null
+++ b/2420/3/views/analysis.erb
@@ -0,0 +1,17 @@
+
+ All comments
+
+ <% for id in @first_id..@last_id %>
+
+ <%= Comment[id].body %> |
+ <%= Comment[id].comment_rating %> |
+
+ <%end%>
+
+
+
\ No newline at end of file
diff --git a/2420/3/views/layout.erb b/2420/3/views/layout.erb
new file mode 100644
index 000000000..c1fc811db
--- /dev/null
+++ b/2420/3/views/layout.erb
@@ -0,0 +1,8 @@
+
+
+ <%= title%>
+
+
+ <%= yield %>
+
+
\ No newline at end of file
diff --git a/2420/3/views/table.erb b/2420/3/views/table.erb
new file mode 100644
index 000000000..88c39469d
--- /dev/null
+++ b/2420/3/views/table.erb
@@ -0,0 +1,17 @@
+
+ Добавьте новый URL:
+
+
+ <% Article.all.each do |article| %>
+
+ <%= article.url %> |
+ <%= article.article_rating %> |
+
+ >Линка
+ |
+
+ <%end%>
+
\ No newline at end of file