diff --git a/2377/.gitignore b/2377/.gitignore
new file mode 100644
index 000000000..1d3ed4c17
--- /dev/null
+++ b/2377/.gitignore
@@ -0,0 +1 @@
+config.yml
diff --git a/2377/3/sinatra/Gemfile b/2377/3/sinatra/Gemfile
new file mode 100644
index 000000000..2221d0dfb
--- /dev/null
+++ b/2377/3/sinatra/Gemfile
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'mechanize'
+gem 'ohm'
+gem 'sinatra'
+
+group :development do
+ gem 'pry'
+ gem 'shotgun'
+end
diff --git a/2377/3/sinatra/Gemfile.lock b/2377/3/sinatra/Gemfile.lock
new file mode 100644
index 000000000..08d778cd0
--- /dev/null
+++ b/2377/3/sinatra/Gemfile.lock
@@ -0,0 +1,72 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ coderay (1.1.2)
+ connection_pool (2.2.2)
+ domain_name (0.5.20180417)
+ unf (>= 0.0.5, < 1.0.0)
+ hiredis (0.6.1)
+ http-cookie (1.0.3)
+ domain_name (~> 0.5)
+ mechanize (2.7.6)
+ domain_name (~> 0.5, >= 0.5.1)
+ http-cookie (~> 1.0)
+ mime-types (>= 1.17.2)
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
+ net-http-persistent (>= 2.5.2)
+ nokogiri (~> 1.6)
+ ntlm-http (~> 0.1, >= 0.1.1)
+ webrobots (>= 0.0.9, < 0.2)
+ method_source (0.9.0)
+ mime-types (3.1)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2016.0521)
+ mini_portile2 (2.3.0)
+ mustermann (1.0.2)
+ nest (3.1.1)
+ redic
+ net-http-digest_auth (1.4.1)
+ net-http-persistent (3.0.0)
+ connection_pool (~> 2.2)
+ nokogiri (1.8.4)
+ mini_portile2 (~> 2.3.0)
+ ntlm-http (0.1.1)
+ ohm (3.1.1)
+ nest (~> 3)
+ redic (~> 1.5.0)
+ stal
+ pry (0.11.3)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ rack (2.0.5)
+ rack-protection (2.0.3)
+ rack
+ redic (1.5.0)
+ hiredis
+ 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)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.7.5)
+ webrobots (0.1.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ mechanize
+ ohm
+ pry
+ shotgun
+ sinatra
+
+BUNDLED WITH
+ 1.16.2
diff --git a/2377/3/sinatra/app.rb b/2377/3/sinatra/app.rb
new file mode 100644
index 000000000..eb6a02800
--- /dev/null
+++ b/2377/3/sinatra/app.rb
@@ -0,0 +1,45 @@
+require 'sinatra/base'
+require_relative 'models/link'
+require_relative 'models/comment'
+require_relative 'parser'
+require_relative 'azure_api'
+require 'ohm'
+require 'yaml'
+# Main class for application
+class MyApp < Sinatra::Base
+ post '/links/new' do
+ link = Link.create link: params[:link]
+ please = Parser.new
+ please.get_comments(link)
+ pray = TextAnalytics.new
+ link.comments.each do |comment|
+ pray.analyse(comment)
+ end
+ total = link.comments.inject(0) { |sum, comment| sum + comment.score.to_i } / link.comments.size
+ link.update score: total
+ redirect '/links'
+ end
+
+ get '/links' do
+ erb :active_page
+ end
+
+ get '/' do
+ erb :main
+ end
+
+ get '/clear' do
+ Ohm.redis.call('FLUSHALL')
+ redirect '/'
+ end
+
+ get '/links/:id' do
+ @comments = Link[params[:id]].comments
+
+ erb :links
+ end
+
+ # $0 is the executed file
+ # __FILE__ is the current file
+ run! if $PROGRAM_NAME == __FILE__
+end
diff --git a/2377/3/sinatra/azure_api.rb b/2377/3/sinatra/azure_api.rb
new file mode 100644
index 000000000..f90881c1b
--- /dev/null
+++ b/2377/3/sinatra/azure_api.rb
@@ -0,0 +1,41 @@
+require 'net/https'
+require 'uri'
+require 'json'
+require_relative 'converter'
+# Analysis via Azure API
+class TextAnalytics
+ def initialize
+ @uri = URI('https://westeurope.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment')
+ end
+
+ def analyse(comment)
+ response = Net::HTTP.start(@uri.host, @uri.port, use_ssl: @uri.scheme == 'https') do |http|
+ http.request request(comment)
+ end
+ update_comment(comment, response)
+ end
+
+ private
+
+ def access_key
+ @access_key = YAML.load_file(File.join(Dir.pwd, 'config.yml'))['access_key']
+ end
+
+ def documents(comment)
+ documents = {}
+ documents['documents'] = [{ 'id' => '1', 'language' => 'ru', 'text' => comment.comment.to_s }]
+ documents
+ end
+
+ def update_comment(comment, response)
+ comment.update score: Converter.new(((JSON response.body)['documents'][0]['score'])).final_value
+ end
+
+ def request(comment)
+ request = Net::HTTP::Post.new(@uri)
+ request['Content-Type'] = 'application/json'
+ request['Ocp-Apim-Subscription-Key'] = access_key
+ request.body = documents(comment).to_json
+ request
+ end
+end
diff --git a/2377/3/sinatra/converter.rb b/2377/3/sinatra/converter.rb
new file mode 100644
index 000000000..4477e7c69
--- /dev/null
+++ b/2377/3/sinatra/converter.rb
@@ -0,0 +1,14 @@
+# Converts things
+class Converter
+ attr_reader :value
+ attr_reader :final_value
+ def initialize(value)
+ @value = value
+ @final_value = convert
+ end
+
+ def convert
+ proportion = 1 / value
+ 200 / proportion - 100
+ end
+end
diff --git a/2377/3/sinatra/models/comment.rb b/2377/3/sinatra/models/comment.rb
new file mode 100644
index 000000000..22d3c1b03
--- /dev/null
+++ b/2377/3/sinatra/models/comment.rb
@@ -0,0 +1,6 @@
+require 'ohm'
+# Describes comment
+class Comment < Ohm::Model
+ attribute :comment
+ attribute :score
+end
diff --git a/2377/3/sinatra/models/link.rb b/2377/3/sinatra/models/link.rb
new file mode 100644
index 000000000..9417db939
--- /dev/null
+++ b/2377/3/sinatra/models/link.rb
@@ -0,0 +1,7 @@
+require 'ohm'
+# Describes link
+class Link < Ohm::Model
+ attribute :link
+ list :comments, :Comment
+ attribute :score
+end
diff --git a/2377/3/sinatra/parser.rb b/2377/3/sinatra/parser.rb
new file mode 100644
index 000000000..9fcf1784c
--- /dev/null
+++ b/2377/3/sinatra/parser.rb
@@ -0,0 +1,29 @@
+require 'open-uri'
+require 'nokogiri'
+require 'net/http'
+require 'json'
+# Parsing of comments
+class Parser
+ ONLINER = 'https://comments.api.onliner.by/news/tech.post/'.freeze
+ def get_comments(link)
+ json_comments = JSON.parse(Net::HTTP.get_response(URI.parse(ONLINER + get_id(link) + '/comments?limit=50')).body)
+ comments = json_comments['comments'].each.map { |hash| hash['text'] }
+ push(comments, link)
+ end
+
+ private
+
+ def push(comments, link)
+ comments.each do |comment|
+ link.comments.push(Comment.create(comment: comment))
+ end
+ end
+
+ def response(link)
+ Net::HTTP.get_response(URI.parse(link.link)).body
+ end
+
+ def get_id(link)
+ Nokogiri::HTML(response(link)).xpath('//span[@news_id]').to_s.match(/\d+/).to_s
+ end
+end
diff --git a/2377/3/sinatra/views/active_page.erb b/2377/3/sinatra/views/active_page.erb
new file mode 100644
index 000000000..5e4bc3f89
--- /dev/null
+++ b/2377/3/sinatra/views/active_page.erb
@@ -0,0 +1,38 @@
+
+
+
+
+ analysis
+
+
+
+
+
+
+
+
+
+
diff --git a/2377/3/sinatra/views/links.erb b/2377/3/sinatra/views/links.erb
new file mode 100644
index 000000000..00ccd8ea6
--- /dev/null
+++ b/2377/3/sinatra/views/links.erb
@@ -0,0 +1,19 @@
+
+
+
+
+ analysis
+
+
+
+ <%if @comments%>
+ <% @comments.each do |comment| %>
+
+ <%=comment.comment%> |
+ <%=comment.score%> |
+ |
+ <% end%>
+ <% end%>
+
+
+
diff --git a/2377/3/sinatra/views/main.erb b/2377/3/sinatra/views/main.erb
new file mode 100644
index 000000000..04cd08ccc
--- /dev/null
+++ b/2377/3/sinatra/views/main.erb
@@ -0,0 +1,15 @@
+
+
+
+
+ analysis
+
+
+
+
+
+