rsodx 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b217ac144c8fbb46a2bb7925dd8bb24c6d994527e395cc5b80d692678b0aafc3
4
- data.tar.gz: 94a126bcac19393eb9eeefdb0188e20003f5c7d2e71dd4e0f609b9525727cfaf
3
+ metadata.gz: 3cf0b729bdc4f7c8028726664039d5370f7a859031cd128edd221d15f479e743
4
+ data.tar.gz: cd2b5dc997bef4c10dc51a0aa7c3e56413f1f55b38be7136240d35b02c66ce5c
5
5
  SHA512:
6
- metadata.gz: afaf0f6269158079ce894bb3ae483c0414bd9c0a76797c0bc2ffa9b958f235a9bbc739205ec7ababae85a1f2d76cc1f27805828b8e920e275eea9ee7e1e645b1
7
- data.tar.gz: 6bc50511150506c1736888779f0564b6c1896b6811c0f0b818f07573431fe733ecc0b21bd2470338e4f156e9d303a96fffdf9ffeef46fc6e85e94167a0019d6a
6
+ metadata.gz: 7905ace36dadb5da1e100d7257f4dba96697eedb1306d229655a4d12e42db9a20d7da40eeb0eec270d1c071c507b26a46fa8d615212e270f610711e7693502e0
7
+ data.tar.gz: 50291c0daaa94f34a7466c2bb15e2528a0aabf8d6be6be272e0953e2e34463670272bd010ef6aea2b38c82a81294e6c1f04b67317240b57fc2361f911ad3b188
data/README.md CHANGED
@@ -69,6 +69,40 @@ bin/rsodx [command] [args]
69
69
 
70
70
  ---
71
71
 
72
+ Конечно! Вот секция для `README.md` на английском — про команды `db:migrate` и `db:rollback`:
73
+
74
+ ---
75
+
76
+ ## 🛠 Database Commands
77
+
78
+ The `rsodx` CLI provides simple tools for running Sequel migrations:
79
+
80
+ ### 🔼 `db:migrate`
81
+
82
+ Runs all pending migrations in `db/migrations`.
83
+
84
+ ```bash
85
+ bin/rsodx db:migrate
86
+ ```
87
+
88
+ - Automatically creates the `schema_migrations` table if it doesn't exist.
89
+ - Supports timestamped migrations (e.g. `20250417061127_create_users.rb`).
90
+ - Prints a success message on completion.
91
+
92
+ ### 🔽 `db:rollback`
93
+
94
+ Rolls back the last executed migration.
95
+
96
+ ```bash
97
+ bin/rsodx db:rollback
98
+ ```
99
+
100
+ - Determines the current version from the `schema_migrations` table.
101
+ - Rolls back to the previous migration based on timestamp.
102
+ - Skips rollback if only one migration is applied.
103
+
104
+ ---
105
+
72
106
  ## 🔧 Generators
73
107
 
74
108
  Generate various application components using simple commands:
data/lib/rsodx/cli/cli.rb CHANGED
@@ -9,6 +9,31 @@ module Rsodx::Cli
9
9
  extend Dry::CLI::Registry
10
10
 
11
11
  def self.setup!
12
+ register_commands_with_alias(
13
+ group: "",
14
+ alias_prefix: "",
15
+ commands: {
16
+ "db:migrate" => ::Rsodx::Cli::Commands::Db::Migrate
17
+ }
18
+ )
19
+
20
+ register_commands_with_alias(
21
+ group: "",
22
+ alias_prefix: "",
23
+ commands: {
24
+ "db:rollback" => ::Rsodx::Cli::Commands::Db::Rollback
25
+ }
26
+ )
27
+
28
+ register_commands_with_alias(
29
+ group: "",
30
+ alias_prefix: "",
31
+ commands: {
32
+ "console" => ::Rsodx::Cli::Commands::Console,
33
+ "c" => ::Rsodx::Cli::Commands::Console
34
+ }
35
+ )
36
+
12
37
  register_commands_with_alias(
13
38
  group: "",
14
39
  alias_prefix: "",
@@ -0,0 +1,33 @@
1
+ require "dry/cli"
2
+ require "irb"
3
+ require "irb/completion"
4
+
5
+ module Rsodx::Cli::Commands
6
+ class Console < Dry::CLI::Command
7
+ desc "Start the Rsodx development console"
8
+
9
+ def call(*)
10
+ project_root = Rsodx.project_root
11
+ environment_path = File.join(project_root, "config", "environment.rb")
12
+
13
+ unless File.exist?(environment_path)
14
+ abort "❌ Could not find config/environment.rb in #{project_root}"
15
+ end
16
+
17
+ require environment_path
18
+
19
+ TOPLEVEL_BINDING.eval('def reload!; Rsodx.reload!; end')
20
+
21
+ puts Rsodx::LOGO
22
+ puts "🔬 Welcome to Rsodx console (#{ENV['RACK_ENV'] || 'development'})"
23
+ puts "Tip: access Rsodx modules, models, services, etc."
24
+
25
+ ARGV.clear
26
+ IRB.start
27
+ rescue LoadError => e
28
+ abort "❌ Failed to load: #{e.message}"
29
+ rescue StandardError => e
30
+ abort "❌ An error occurred: #{e.message}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ require "sequel/extensions/migration"
2
+
3
+ module Rsodx::Cli::Commands::Db
4
+ class Migrate < Dry::CLI::Command
5
+ desc "Migrate"
6
+
7
+ def call(*)
8
+ project_root = Rsodx.project_root
9
+ environment_path = File.join(project_root, "config", "environment.rb")
10
+
11
+ unless File.exist?(environment_path)
12
+ abort "❌ Could not find config/environment.rb in #{project_root}"
13
+ end
14
+
15
+ require environment_path
16
+
17
+ Sequel::Migrator.run(Rsodx::Connect.db, "db/migrations")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require "sequel/extensions/migration"
2
+
3
+ module Rsodx::Cli::Commands::Db
4
+ class Rollback < Dry::CLI::Command
5
+ desc "Rollback"
6
+
7
+ def call(*)
8
+ project_root = Rsodx.project_root
9
+ environment_path = File.join(project_root, "config", "environment.rb")
10
+
11
+ unless File.exist?(environment_path)
12
+ abort "❌ Could not find config/environment.rb in #{project_root}"
13
+ end
14
+
15
+ require environment_path
16
+ migration_table = :schema_migrations
17
+ migration_dir = 'db/migrations'
18
+
19
+ versions = Rsodx::Connect.db[migration_table].select(:filename).map { |r| r[:filename] }
20
+ version_numbers = versions.map { |f| f.to_s[/^\d+/].to_i }.sort
21
+
22
+ current_version = version_numbers.last
23
+ previous_version = version_numbers[-2] || 0
24
+ Sequel::Migrator.run(Rsodx::Connect.db, migration_dir, target: previous_version)
25
+ end
26
+ end
27
+ end
@@ -28,8 +28,13 @@ module Rsodx::Cli::Commands
28
28
  private
29
29
 
30
30
  def create_folders
31
- FOLDERS.each do |path|
32
- FileUtils.mkdir_p(File.join(@app_path, path))
31
+ KEEPABLE_FOLDERS.each do |folder|
32
+ FileUtils.mkdir_p(File.join(@app_path, folder))
33
+ FileUtils.touch(File.join(@app_path, folder, '.keep'))
34
+ end
35
+
36
+ FRAMEWORK_FOLDERS.each do |folder|
37
+ FileUtils.mkdir_p(File.join(@app_path, folder))
33
38
  end
34
39
  end
35
40
 
@@ -41,18 +46,16 @@ module Rsodx::Cli::Commands
41
46
  write("config/environment.rb", ENV_LOADER)
42
47
  write("Rakefile", RAKEFILE)
43
48
  write("app/controllers/app_controller.rb", APP_CONTROLLER)
44
- write("app/services/app_services.rb", APP_SERVICE)
49
+ write("app/services/app_service.rb", APP_SERVICE)
45
50
  write("app/serializers/app_serializer.rb", APP_SERIALIZER)
46
51
  write("app/presenters/app_presenter.rb", APP_PRESENTER)
47
52
  write("app/app.rb", APP)
48
53
  write("app/router.rb", ROUTE)
49
54
  write("config/environments/development.rb", "")
50
55
  write("config.ru", CONFIGRU)
51
- write("bin/console", CONSOLE)
52
56
  write("bin/rsodx", BINRSODX)
53
57
 
54
58
  FileUtils.chmod("+x", File.join(@app_path, "bin/rsodx"))
55
- FileUtils.chmod("+x", File.join(@app_path, "bin/console"))
56
59
  end
57
60
 
58
61
  def write(relative_path, content)
@@ -2,8 +2,8 @@ module Rsodx::Cli::Commands::ScaffoldCommon
2
2
  RUBY_VERSION = "3.4.2".freeze
3
3
 
4
4
  GITIGNORE = <<~GITIGNORE.freeze
5
- .env
6
- tmp/
5
+ .env
6
+ tmp/
7
7
  GITIGNORE
8
8
 
9
9
  # path: "../rsodx"
@@ -25,32 +25,15 @@ module Rsodx::Cli::Commands::ScaffoldCommon
25
25
  Rsodx::CLI.call
26
26
  BINRSODX
27
27
 
28
- CONSOLE = <<~CONSOLE.freeze
29
- #!/usr/bin/env ruby
30
-
31
- require "irb"
32
- require "irb/completion"
33
-
34
- def reload!
35
- puts "🔄 Reloading..."
36
- load File.expand_path("../config/environment.rb", __dir__)
37
- end
38
-
39
- require_relative "../config/environment"
40
-
41
- puts "🔬 Welcome to Rsodx console (#{ENV['RACK_ENV'] || 'development'})"
42
- puts "Tip: access Rsodx modules, models, services, etc."
43
-
44
- IRB.start
45
- CONSOLE
46
-
47
28
  CONFIGRU = <<~RACK.freeze
48
29
  require_relative "./app/app"
49
30
  run App
50
31
  RACK
51
32
 
52
33
  ENV_LOADER = <<~ENV_LOADER.freeze
34
+ require "zeitwerk"
53
35
  require "rsodx"
36
+
54
37
  Rsodx::Environment.load_dotenv(ENV["RACK_ENV"] || "development")
55
38
 
56
39
  Rsodx.configure do |config|
@@ -59,7 +42,8 @@ module Rsodx::Cli::Commands::ScaffoldCommon
59
42
  Rsodx::Connect.connect
60
43
 
61
44
  Rsodx::Environment.load_initializers(File.expand_path("../..", __FILE__))
62
- Rsodx::Boot.load_app_structure(File.expand_path("../..", __FILE__))
45
+
46
+ Rsodx.loader
63
47
  ENV_LOADER
64
48
 
65
49
  ROUTE = <<~ROUTE.freeze
@@ -106,7 +90,23 @@ module Rsodx::Cli::Commands::ScaffoldCommon
106
90
  DATABASE_URL=postgres://rsodx:paSs4321@localhost:5432/rsodx_development
107
91
  ENVFILE
108
92
 
109
- FOLDERS = %w[app/controllers app/services app/models app/presenters
110
- app/serializers config/initializers
111
- config/environments db/migrations spec bin].freeze
93
+ KEEPABLE_FOLDERS = %w[
94
+ lib
95
+ app/controllers
96
+ app/workers
97
+ app/services
98
+ app/models
99
+ app/presenters
100
+ app/serializers
101
+ config/initializers
102
+ config/environments
103
+ db/migrations
104
+ spec
105
+ ].freeze
106
+
107
+ FRAMEWORK_FOLDERS = %w[
108
+ bin
109
+ config
110
+ ].freeze
111
+
112
112
  end
@@ -1,9 +1,20 @@
1
1
  module Rsodx
2
2
  class Configuration
3
- attr_accessor :database_url
3
+ attr_accessor :database_url, :logger, :appname
4
4
 
5
5
  def initialize
6
- @database_url = ENV["DATABASE_URL"]
6
+ @appname = Rsodx::RSODX_NAME
7
+ init_database
8
+ init_logger
9
+ end
10
+
11
+ private
12
+
13
+ def init_database
14
+ @database_url = ENV['DATABASE_URL']
15
+ end
16
+ def init_logger
17
+ @logger ||= Rsodx::Logger.new(Rsodx::LoggerAdapter.new($stdout))
7
18
  end
8
19
  end
9
20
  end
@@ -2,12 +2,22 @@ require "forwardable"
2
2
 
3
3
  module Rsodx
4
4
  module Delegate
5
- def delegate(*methods, to:)
5
+ def delegate(*methods, to:, prefix: nil)
6
6
  raise ArgumentError, "Missing target for delegation (to:)" unless to
7
7
 
8
8
  mod = Module.new do
9
9
  extend Forwardable
10
- def_delegators to, *methods
10
+
11
+ methods.each do |method_name|
12
+ delegated_name = if prefix
13
+ prefix_str = prefix == true ? to.to_s : prefix.to_s
14
+ "#{prefix_str}_#{method_name}"
15
+ else
16
+ method_name
17
+ end
18
+
19
+ def_delegator to, method_name, delegated_name
20
+ end
11
21
  end
12
22
 
13
23
  include mod
@@ -2,11 +2,17 @@ module Rsodx
2
2
  module Environment
3
3
  def self.load_dotenv(env = nil)
4
4
  require "dotenv"
5
- Dotenv.load('.env', ".env.#{env}") if env
5
+ Rsodx.instance_variable_set(:@env, env.to_s.freeze) unless Rsodx.instance_variable_defined?(:@env)
6
+
7
+ Dotenv.overload(".env.#{env}") if env
6
8
  end
7
9
 
8
10
  def self.load_initializers(app_root)
9
11
  Dir[File.join(app_root, "config", "initializers", "*.rb")].sort.each { |file| require file }
10
12
  end
13
+
14
+ def self.env
15
+ @env || "development"
16
+ end
11
17
  end
12
18
  end
@@ -0,0 +1,51 @@
1
+ require 'json'
2
+ require 'time'
3
+ require 'syslog/logger'
4
+
5
+ module Rsodx
6
+ class Logger
7
+ attr_accessor :adapter, :options
8
+
9
+ LEVELS = %i[info debug warn error fatal].freeze
10
+ OPTIONS = { with_backtrace: false }.freeze
11
+ LogEntry = Struct.new(:timestamp, :appname, :level, :code, :message, :context, :backtrace)
12
+
13
+ def initialize(adapter, options = {})
14
+ raise ArgumentError, 'Invalid LoggerAdapter' unless adapter.is_a?(LoggerAdapter)
15
+ @adapter = adapter
16
+ @options = OPTIONS.merge(options).slice(*OPTIONS.keys)
17
+ end
18
+
19
+ def log(level = :info, code:, message:, context: {}, backtrace: nil)
20
+ raise ArgumentError, "Invalid log level: #{level}" unless LEVELS.include?(level)
21
+
22
+ entry = LogEntry.new(
23
+ timestamp: Time.now.utc.iso8601,
24
+ appname: appname,
25
+ level: level,
26
+ code: code,
27
+ message: message,
28
+ context: context,
29
+ backtrace: include_backtrace?(level) ? (backtrace || caller).take(10) : nil
30
+ )
31
+
32
+ adapter.puts(entry)
33
+ end
34
+
35
+ LEVELS.each do |level|
36
+ define_method(level) do |code, message, context = {}|
37
+ log(level, code: code, message: message, context: context)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def include_backtrace?(level)
44
+ options[:with_backtrace] || level == :debug
45
+ end
46
+
47
+ def appname
48
+ Rsodx.config.appname
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,32 @@
1
+ module Rsodx
2
+ class LoggerAdapter
3
+ def initialize(target)
4
+ @target = target
5
+ end
6
+
7
+ def puts(log)
8
+ case @target
9
+ when IO
10
+ @target.puts(log_format(log).to_json)
11
+ when ::Logger
12
+ @target.send(log.level, log_format(log).to_json)
13
+ when Syslog::Logger
14
+ @target.send(log.level, "[#{log.appname}] [#{log.code}] #{log.message} #{log.context}")
15
+ else
16
+ raise "Unsupported log target: #{@target.class}"
17
+ end
18
+ end
19
+
20
+ def log_format(log)
21
+ {
22
+ app: log.appname,
23
+ timestamp: log.timestamp,
24
+ level: log.level,
25
+ code: log.code,
26
+ message: log.message,
27
+ context: (log.context.empty? ? nil : log.context),
28
+ backtrace: log.backtrace
29
+ }.compact
30
+ end
31
+ end
32
+ end
data/lib/rsodx/service.rb CHANGED
@@ -6,6 +6,7 @@ module Rsodx
6
6
  extend Delegate
7
7
 
8
8
  delegate :params, :object, to: :context
9
+ delegate :log, :info, :debug, :warn, :fatal, :error, to: :logger, prefix: :log
9
10
 
10
11
  class << self
11
12
  attr_accessor :contract_class
@@ -25,18 +26,11 @@ module Rsodx
25
26
  def halt(code, message)
26
27
  log_error(code, message)
27
28
  context.fail!(error_code: code, error: message)
29
+ Rsodx.config.logger&.error(code, message, context)
28
30
  end
29
31
 
30
- private
31
-
32
- def log_error(code, message)
33
- puts JSON.pretty_generate({
34
- level: "error",
35
- code: code,
36
- message: message,
37
- context: context.to_h,
38
- backtrace: caller
39
- })
32
+ def logger
33
+ Rsodx.config.logger
40
34
  end
41
35
  end
42
36
  end
data/lib/rsodx/tasks.rb CHANGED
@@ -1,15 +1,2 @@
1
1
  return unless defined?(Rake::DSL) rescue false
2
2
  include Rake::DSL if defined?(Rake::DSL)
3
-
4
- require "sequel/extensions/migration"
5
-
6
- namespace :db do
7
- task :migrate do
8
- Sequel::Migrator.run(Rsodx::Connect.db, "db/migrations")
9
- end
10
-
11
- task :rollback do
12
- target = Sequel::Migrator.apply(Rsodx::Connect.db, "db/migrations", :down) - 1
13
- Sequel::Migrator.run(Rsodx::Connect.db, "db/migrations", target: target)
14
- end
15
- end
data/lib/rsodx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rsodx
4
- VERSION = "0.0.5"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/rsodx.rb CHANGED
@@ -14,6 +14,8 @@ Dir.glob("#{base}/rsodx/**/*.rb").sort.each do |file|
14
14
  end
15
15
 
16
16
  module Rsodx
17
+ RSODX_NAME = 'Rsodx'.freeze
18
+
17
19
  class << self
18
20
  attr_accessor :config
19
21
 
@@ -22,6 +24,40 @@ module Rsodx
22
24
  yield(config)
23
25
  end
24
26
  end
27
+
28
+ def self.project_root
29
+ @root ||= Dir.pwd
30
+ end
31
+
32
+ def self.loader
33
+ @loader ||= begin
34
+ loader = Zeitwerk::Loader.new
35
+
36
+ # need to be merged with ScaffoldCommon
37
+ %w[
38
+ app/models
39
+ app/services
40
+ app/workers
41
+ app/presenters
42
+ app/serializers
43
+ app/controllers
44
+ app/lib
45
+ ].each do |subdir|
46
+ path = File.join(project_root, subdir)
47
+ loader.push_dir(path) if Dir.exist?(path)
48
+ end
49
+
50
+ loader.enable_reloading
51
+ loader.setup
52
+ loader
53
+ end
54
+ end
55
+
56
+ def self.reload!
57
+ puts "🔄 Reloading..."
58
+ loader.reload
59
+ end
25
60
  end
26
61
 
27
62
  Rsodx.config ||= Rsodx::Configuration.new
63
+ Rsodx.loader
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsodx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Pervushin
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-16 00:00:00.000000000 Z
10
+ date: 2025-05-15 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake
@@ -191,6 +191,62 @@ dependencies:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
193
  version: '1.2'
194
+ - !ruby/object:Gem::Dependency
195
+ name: zeitwerk
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '2.7'
201
+ type: :runtime
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '2.7'
208
+ - !ruby/object:Gem::Dependency
209
+ name: rdoc
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '6.13'
215
+ type: :runtime
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: '6.13'
222
+ - !ruby/object:Gem::Dependency
223
+ name: irb
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: '1.15'
229
+ type: :runtime
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - "~>"
234
+ - !ruby/object:Gem::Version
235
+ version: '1.15'
236
+ - !ruby/object:Gem::Dependency
237
+ name: syslog
238
+ requirement: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - "~>"
241
+ - !ruby/object:Gem::Version
242
+ version: '0.3'
243
+ type: :runtime
244
+ prerelease: false
245
+ version_requirements: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - "~>"
248
+ - !ruby/object:Gem::Version
249
+ version: '0.3'
194
250
  description: Rsodx is a lightweight Ruby microframework designed for modular, service-oriented
195
251
  applications. Built with simplicity and performance in mind, it's perfect for small
196
252
  web apps, microservices, and CLI tools.
@@ -201,7 +257,6 @@ executables:
201
257
  extensions: []
202
258
  extra_rdoc_files: []
203
259
  files:
204
- - LICENSE.txt
205
260
  - README.md
206
261
  - bin/console
207
262
  - bin/rsodx
@@ -211,6 +266,9 @@ files:
211
266
  - lib/rsodx/base.rb
212
267
  - lib/rsodx/boot.rb
213
268
  - lib/rsodx/cli/cli.rb
269
+ - lib/rsodx/cli/commands/console.rb
270
+ - lib/rsodx/cli/commands/db/migrate.rb
271
+ - lib/rsodx/cli/commands/db/rollback.rb
214
272
  - lib/rsodx/cli/commands/generator.rb
215
273
  - lib/rsodx/cli/commands/generators/action.rb
216
274
  - lib/rsodx/cli/commands/generators/controller.rb
@@ -229,6 +287,8 @@ files:
229
287
  - lib/rsodx/environment.rb
230
288
  - lib/rsodx/error.rb
231
289
  - lib/rsodx/headers.rb
290
+ - lib/rsodx/logger.rb
291
+ - lib/rsodx/logger_adapter.rb
232
292
  - lib/rsodx/presenter.rb
233
293
  - lib/rsodx/request.rb
234
294
  - lib/rsodx/router.rb
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2025 Первушин
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.