amdgpu_fan 0.4.0 → 0.5.0
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 +4 -4
- data/README.md +30 -21
- data/bin/amdgpu_fan +2 -2
- data/config/environment.rb +7 -1
- data/lib/amdgpu_fan.rb +7 -0
- data/lib/amdgpu_fan/cli.rb +165 -0
- data/lib/amdgpu_fan/connector.rb +60 -0
- data/lib/amdgpu_fan/mixin/cli_output_format.rb +25 -0
- data/lib/amdgpu_fan/mixin/fan.rb +43 -0
- data/lib/amdgpu_fan/mixin/sys_write.rb +15 -0
- data/lib/amdgpu_fan/service.rb +157 -0
- metadata +10 -6
- data/lib/amdgpu_fan_cli.rb +0 -167
- data/lib/amdgpu_service.rb +0 -177
- data/lib/radeon_r_black_red_100x100.ascii +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 822ba3e84cdd6cb64680ace91e696351c3ac8f61fe7344554304be517c1ee141
|
4
|
+
data.tar.gz: b74858f3916aec38afb02134694011f59f4c672d276dd4905e9da6accee69333
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1798fa2cb6a578717c75d898501833e75e27fc8efd14881954c8a7cdf53e71a0dc1dfb0cba6b51b8b96572943761d6d9f23be33f26f8bc6ee3c42e38f017ab7c
|
7
|
+
data.tar.gz: 95df0c6e478a1cbe580695c9be8cf123e555ec76ef767eb5a91b24d174693667cf33b0dabcc6a3ddd45cdfd54a7efd070317e6a74fc63395f2b96d207b77e0eb
|
data/README.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# amdgpu_fan
|
2
2
|
|
3
3
|
[](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb) [](https://codeclimate.com/github/HarlemSquirrel/amdgpu-fan-rb/maintainability)
|
4
4
|
|
5
|
-
A Ruby CLI to read and set
|
5
|
+
A Ruby CLI to read and set fan speed, power profiles, and more for AMD Radeon graphics cards running on the AMDGPU Linux driver.
|
6
6
|
|
7
|
-
|
7
|
+
**amdgpu_fan** aims to provide a more user friendly interface on top of [sysfs](https://en.wikipedia.org/wiki/Sysfs) for displaying statistics and interacting with AMD Radeon graphics hardware running on the [AMDgpu](https://dri.freedesktop.org/docs/drm/gpu/amdgpu.html) driver.
|
8
|
+
|
9
|
+
#### Further reading
|
10
|
+
|
11
|
+
- https://wiki.archlinux.org/index.php/AMDGPU#Overclocking
|
12
|
+
- https://wiki.archlinux.org/index.php/Fan_speed_control#AMDGPU_sysfs_fan_control
|
13
|
+
- https://phoronix.com/scan.php?page=news_item&px=AMDGPU-Quick-WattMan-Cap-Test
|
8
14
|
|
9
15
|
## Installation
|
10
16
|
|
@@ -28,25 +34,28 @@ gem install amdgpu_fan
|
|
28
34
|
## Usage
|
29
35
|
|
30
36
|
```
|
31
|
-
➤ bin/amdgpu_fan
|
37
|
+
➤ bin/amdgpu_fan help
|
32
38
|
Commands:
|
33
|
-
amdgpu_fan
|
34
|
-
amdgpu_fan
|
35
|
-
amdgpu_fan
|
36
|
-
amdgpu_fan
|
37
|
-
amdgpu_fan
|
38
|
-
amdgpu_fan
|
39
|
-
amdgpu_fan
|
40
|
-
amdgpu_fan status [--logo]
|
41
|
-
amdgpu_fan watch [SECONDS]
|
42
|
-
amdgpu_fan watch_csv [SECONDS]
|
43
|
-
|
44
|
-
➤ amdgpu_fan status
|
45
|
-
📺
|
46
|
-
📄
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
amdgpu_fan connectors # View the status of the display connectors.
|
40
|
+
amdgpu_fan fan # View fan details.
|
41
|
+
amdgpu_fan fan_set PERCENTAGE/AUTO # Set fan speed to percentage or automatic mode. (requires sudo)
|
42
|
+
amdgpu_fan help [COMMAND] # Describe available commands or one specific command
|
43
|
+
amdgpu_fan profile # View power profile details.
|
44
|
+
amdgpu_fan profile_auto # Set the power profile to automatic mode.
|
45
|
+
amdgpu_fan profile_force PROFILE_NUM # Manually set a power profile. (requires sudo)
|
46
|
+
amdgpu_fan status [--logo] # View device info, current fan speed, and temperature.
|
47
|
+
amdgpu_fan watch [SECONDS] # Watch fan speed, load, power, and temperature refreshed every n seconds.
|
48
|
+
amdgpu_fan watch_csv [SECONDS] # Watch stats in CSV format refreshed every n seconds defaulting to 1 second.
|
49
|
+
|
50
|
+
➤ bin/amdgpu_fan status
|
51
|
+
📺 GPU: Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO
|
52
|
+
📄 vBIOS: 113-C8800100-102
|
53
|
+
⏰ Clocks: 724Mhz Core, 500Mhz Memory
|
54
|
+
💾 Memory: 4096 MiB
|
55
|
+
🌀 Fan: auto mode running at 1809 rpm (48%)
|
56
|
+
🌞 Temp: 21.0°C
|
57
|
+
⚡ Power: 3D_FULL_SCREEN profile in performance mode using 16.2 / 300.0 Watts (5%)
|
58
|
+
⚖ Load: [ ]0%
|
50
59
|
|
51
60
|
➤ bin/amdgpu_fan watch 3
|
52
61
|
Watching Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO every 3 second(s)...
|
data/bin/amdgpu_fan
CHANGED
data/config/environment.rb
CHANGED
@@ -2,4 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'thor'
|
4
4
|
|
5
|
-
require_relative '../lib/
|
5
|
+
require_relative '../lib/amdgpu_fan'
|
6
|
+
|
7
|
+
require_relative '../lib/amdgpu_fan/mixin/cli_output_format'
|
8
|
+
require_relative '../lib/amdgpu_fan/mixin/sys_write'
|
9
|
+
|
10
|
+
require_relative '../lib/amdgpu_fan/service'
|
11
|
+
require_relative '../lib/amdgpu_fan/cli'
|
data/lib/amdgpu_fan.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
# The command-line interface class
|
5
|
+
class Cli < Thor
|
6
|
+
include CliOutputFormat
|
7
|
+
|
8
|
+
WATCH_FIELD_SEPARATOR = ' | '
|
9
|
+
|
10
|
+
desc 'connectors', 'View the status of the display connectors.'
|
11
|
+
def connectors
|
12
|
+
amdgpu_service.connectors.each do |connector|
|
13
|
+
puts "#{connector.type} #{connector.index}:\t" +
|
14
|
+
(connector.connected? ? connector.display_name : connector.status)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'profile', 'View power profile details.'
|
19
|
+
def profile
|
20
|
+
puts amdgpu_service.profile_summary
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'profile_auto', 'Set the power profile to automatic mode.'
|
24
|
+
def profile_auto
|
25
|
+
amdgpu_service.profile_auto
|
26
|
+
puts amdgpu_service.profile_summary
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'profile_force PROFILE_NUM', 'Manually set a power profile. (requires sudo)'
|
30
|
+
def profile_force(state)
|
31
|
+
amdgpu_service.profile_force = state
|
32
|
+
puts amdgpu_service.profile_summary
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'fan', 'View fan details.'
|
36
|
+
def fan
|
37
|
+
puts fan_status
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'fan_set PERCENTAGE/AUTO', 'Set fan speed to percentage or automatic mode. (requires sudo)'
|
41
|
+
def fan_set(value)
|
42
|
+
if value.strip.casecmp('auto').zero?
|
43
|
+
amdgpu_service.fan_mode = :auto
|
44
|
+
else
|
45
|
+
return puts 'Invalid percentage' unless (0..100).cover?(value.to_i)
|
46
|
+
|
47
|
+
amdgpu_service.fan_speed = value
|
48
|
+
end
|
49
|
+
puts fan_status
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'status [--logo]', 'View device info, current fan speed, and temperature.'
|
53
|
+
def status(option = nil)
|
54
|
+
puts radeon_logo if option == '--logo'
|
55
|
+
puts "👾 #{'GPU:'.ljust(9)} #{amdgpu_service.name}",
|
56
|
+
"📄 #{'vBIOS:'.ljust(9)} #{amdgpu_service.vbios_version}",
|
57
|
+
"📺 Displays: #{amdgpu_service.connectors.map(&:display_name).compact.join(',')}",
|
58
|
+
"⏰ #{'Clocks:'.ljust(9)} #{clock_status}",
|
59
|
+
"💾 #{'Memory:'.ljust(9)} #{mem_total_mibibyes}",
|
60
|
+
"🌀 #{'Fan:'.ljust(9)} #{fan_status}",
|
61
|
+
"🌞 #{'Temp:'.ljust(9)} #{amdgpu_service.temperature}°C",
|
62
|
+
"⚡ #{'Power:'.ljust(9)} #{amdgpu_service.profile_mode} profile in " \
|
63
|
+
"#{amdgpu_service.power_dpm_state} mode using " \
|
64
|
+
"#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
|
65
|
+
"(#{amdgpu_service.power_draw_percent}%)",
|
66
|
+
"⚖ #{'Load:'.ljust(9)} #{percent_meter amdgpu_service.busy_percent, 20}"
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
|
70
|
+
'refreshed every n seconds.'
|
71
|
+
def watch(seconds = 1)
|
72
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
73
|
+
|
74
|
+
puts "Watching #{amdgpu_service.name} every #{seconds} second(s)...",
|
75
|
+
' <Press Ctrl-C to exit>'
|
76
|
+
|
77
|
+
trap 'SIGINT' do
|
78
|
+
puts "\nAnd now the watch is ended."
|
79
|
+
exit 0
|
80
|
+
end
|
81
|
+
|
82
|
+
loop do
|
83
|
+
time = Time.now
|
84
|
+
puts [time.strftime('%F %T'), summary_clock, summary_fan, summary_load, summary_power,
|
85
|
+
summary_temp].join(WATCH_FIELD_SEPARATOR)
|
86
|
+
|
87
|
+
# It can take a second or two to run the above so we remove them from the wait
|
88
|
+
# here to get a more consistant watch interval.
|
89
|
+
sec_left_to_wait = time.to_i + seconds.to_i - Time.now.to_i
|
90
|
+
sleep sec_left_to_wait if sec_left_to_wait.positive?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
|
95
|
+
'refreshed every n seconds defaulting to 1 second.'
|
96
|
+
def watch_csv(seconds = 1)
|
97
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
98
|
+
|
99
|
+
puts 'Timestamp, Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm), '\
|
100
|
+
'Load (%),Power (Watts),Temp (°C)'
|
101
|
+
|
102
|
+
trap 'SIGINT' do
|
103
|
+
exit 0
|
104
|
+
end
|
105
|
+
|
106
|
+
loop do
|
107
|
+
puts [Time.now.strftime('%F %T'),
|
108
|
+
amdgpu_service.core_clock,
|
109
|
+
amdgpu_service.memory_clock,
|
110
|
+
amdgpu_service.fan_speed_rpm,
|
111
|
+
amdgpu_service.busy_percent,
|
112
|
+
amdgpu_service.power_draw,
|
113
|
+
amdgpu_service.temperature].join(',')
|
114
|
+
sleep seconds.to_i
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def amdgpu_service
|
121
|
+
@amdgpu_service ||= AmdgpuFan::Service.new
|
122
|
+
end
|
123
|
+
|
124
|
+
def clock_status
|
125
|
+
"#{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory"
|
126
|
+
end
|
127
|
+
|
128
|
+
def fan_status
|
129
|
+
"#{amdgpu_service.fan_mode} mode running at " \
|
130
|
+
"#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
|
131
|
+
end
|
132
|
+
|
133
|
+
def mem_total_mibibyes
|
134
|
+
"#{amdgpu_service.memory_total / (2**20)} MiB"
|
135
|
+
end
|
136
|
+
|
137
|
+
def power_max
|
138
|
+
format('%<num>0.2f', num: amdgpu_service.power_max)
|
139
|
+
end
|
140
|
+
|
141
|
+
def summary_clock
|
142
|
+
"Core: #{amdgpu_service.core_clock.rjust(7)}#{WATCH_FIELD_SEPARATOR}"\
|
143
|
+
"Memory: #{amdgpu_service.memory_clock.rjust(7)}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def summary_fan
|
147
|
+
fan_speed_string = "#{amdgpu_service.fan_speed_rpm} rpm".rjust(8)
|
148
|
+
"Fan: #{fan_speed_string} #{percent_meter(amdgpu_service.fan_speed_percent)}"
|
149
|
+
end
|
150
|
+
|
151
|
+
def summary_load
|
152
|
+
"Load: #{percent_meter amdgpu_service.busy_percent}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def summary_power
|
156
|
+
"Power: #{format('%<num>0.02f', num: amdgpu_service.power_draw).rjust(power_max.length)} W" \
|
157
|
+
" #{percent_meter amdgpu_service.power_draw_percent}"
|
158
|
+
end
|
159
|
+
|
160
|
+
def summary_temp
|
161
|
+
temp_string = "#{amdgpu_service.temperature}°C".rjust(7)
|
162
|
+
"Temp: #{temp_string}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
## Connector
|
5
|
+
#
|
6
|
+
# A model class for a GPU connector
|
7
|
+
class Connector
|
8
|
+
EDID_DESCRIPTORS_CONF = {
|
9
|
+
display_descriptor_leading_bytes: String.new('\x00\xFC\x00', encoding: 'ascii-8bit'),
|
10
|
+
index_range: (54..125)
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
|
14
|
+
attr_reader :card_num, :dir_path, :index, :type
|
15
|
+
|
16
|
+
class << self
|
17
|
+
##
|
18
|
+
# Return an array of connector objects for the provided card number.
|
19
|
+
# The files are sorted to improve how they are displayed to the user.
|
20
|
+
def where(card_num:)
|
21
|
+
Dir["/sys/class/drm/card#{card_num}/card#{card_num}-*"].sort.map do |dir_path|
|
22
|
+
Connector.new card_num: card_num,
|
23
|
+
dir_path: dir_path,
|
24
|
+
index: dir_path[-1],
|
25
|
+
type: dir_path.slice(/(?<=card#{card_num}-)[A-Z]+/)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(card_num:, dir_path:, index:, type:)
|
31
|
+
@card_num = card_num
|
32
|
+
@dir_path = dir_path
|
33
|
+
@index = index
|
34
|
+
@type = type
|
35
|
+
end
|
36
|
+
|
37
|
+
def connected?
|
38
|
+
status.casecmp('connected').zero?
|
39
|
+
end
|
40
|
+
|
41
|
+
def display_name
|
42
|
+
return if edid.to_s.empty?
|
43
|
+
|
44
|
+
edid.slice(EDID_DESCRIPTORS_CONF[:index_range])
|
45
|
+
.scan(/(?<=#{EDID_DESCRIPTORS_CONF[:display_descriptor_leading_bytes]}).{1,13}/)
|
46
|
+
.first
|
47
|
+
.strip
|
48
|
+
end
|
49
|
+
|
50
|
+
def status
|
51
|
+
File.read(File.join(dir_path, 'status')).strip
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def edid
|
57
|
+
File.read("#{dir_path}/edid", encoding: 'ascii-8bit')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
# A mixin to help with CLI output formatting
|
5
|
+
module CliOutputFormat
|
6
|
+
METER_CHAR = '*'
|
7
|
+
TIME_FORMAT = '%F %T'
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def current_time
|
12
|
+
Time.now.strftime(TIME_FORMAT)
|
13
|
+
end
|
14
|
+
|
15
|
+
def percent_meter(percent, length = 10)
|
16
|
+
progress_bar_count = (length * percent.to_f / 100).round
|
17
|
+
percent_string = "#{format '%<num>0.2i', num: percent}%".ljust(3)
|
18
|
+
"[#{METER_CHAR * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent_string}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def radeon_logo
|
22
|
+
File.read(File.join(__dir__, '../../../assets/radeon_r_black_red_100x100.ascii'))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
##
|
5
|
+
# A mixin to read fan details and validate input
|
6
|
+
module Fan
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def fan_file(type)
|
11
|
+
@fan_file ||= {}
|
12
|
+
@fan_file[type] ||= "#{base_hwmon_dir}/fan1_#{type}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def fan_mode_file
|
16
|
+
@fan_mode_file ||= "#{base_hwmon_dir}/pwm1_enable"
|
17
|
+
end
|
18
|
+
|
19
|
+
def fan_power_file
|
20
|
+
@fan_power_file ||= "#{base_hwmon_dir}/pwm1"
|
21
|
+
end
|
22
|
+
|
23
|
+
def fan_speed_raw
|
24
|
+
File.read(fan_power_file).strip
|
25
|
+
end
|
26
|
+
|
27
|
+
def fan_raw_speeds(type)
|
28
|
+
@fan_raw_speeds ||= {}
|
29
|
+
@fan_raw_speeds[type] ||= File.read(Dir.glob("#{base_card_dir}/**/pwm1_#{type}").first).to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Validate the raw fan speed is between the minimum and maximum values
|
34
|
+
# read from sysfs.
|
35
|
+
def valid_fan_raw_speed?(raw)
|
36
|
+
!raw.nil? && (fan_raw_speeds(:min)..fan_raw_speeds(:max)).cover?(raw.to_i)
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_fan_percent_speed?(percent)
|
40
|
+
(1..100.to_i).cover?(percent.to_i)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
# A mixin to help with writing to system files
|
5
|
+
module SysWrite
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
##
|
10
|
+
# Write to a system file with elevated priviledges.
|
11
|
+
def sudo_write(file_path, value)
|
12
|
+
`echo "#{value}" | sudo tee #{file_path}`
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'mixin/fan'
|
4
|
+
require_relative 'mixin/sys_write'
|
5
|
+
|
6
|
+
require_relative 'connector'
|
7
|
+
|
8
|
+
module AmdgpuFan
|
9
|
+
## AmdgpuService
|
10
|
+
#
|
11
|
+
# A service class for reading and interacting with AMD radeon graphics cards
|
12
|
+
# through the amdgpu Linux kernel driver.
|
13
|
+
class Service
|
14
|
+
include Fan
|
15
|
+
include SysWrite
|
16
|
+
|
17
|
+
BASE_FOLDER = '/sys/class/drm'
|
18
|
+
FAN_MODES = { '1' => 'manual', '2' => 'auto' }.freeze
|
19
|
+
|
20
|
+
attr_reader :card_num
|
21
|
+
|
22
|
+
class Error < StandardError; end
|
23
|
+
|
24
|
+
def initialize(card_num: 0)
|
25
|
+
@card_num = card_num
|
26
|
+
end
|
27
|
+
|
28
|
+
def busy_percent
|
29
|
+
File.read("#{base_card_dir}/gpu_busy_percent").strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def connectors
|
33
|
+
@connectors ||= Connector.where card_num: card_num
|
34
|
+
end
|
35
|
+
|
36
|
+
def core_clock
|
37
|
+
clock_from_pp_file "#{base_card_dir}/pp_dpm_sclk"
|
38
|
+
end
|
39
|
+
|
40
|
+
def fan_mode
|
41
|
+
FAN_MODES[File.read(fan_mode_file).strip] || 'unknown'
|
42
|
+
end
|
43
|
+
|
44
|
+
def fan_mode=(mode)
|
45
|
+
sudo_write fan_mode_file, FAN_MODES.key(mode.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
def fan_speed=(value)
|
49
|
+
if valid_fan_percent_speed?(value)
|
50
|
+
new_raw = (value.to_f / 100 * fan_raw_speeds(:max).to_i).round
|
51
|
+
elsif valid_fan_raw_speed?(value)
|
52
|
+
new_raw = value
|
53
|
+
end
|
54
|
+
|
55
|
+
raise(self.class::Error, 'Invalid fan speed provided') if new_raw.to_s.empty?
|
56
|
+
|
57
|
+
self.fan_mode = :manual unless fan_mode == 'manual'
|
58
|
+
|
59
|
+
sudo_write fan_power_file, new_raw
|
60
|
+
end
|
61
|
+
|
62
|
+
def fan_speed_percent
|
63
|
+
(fan_speed_raw.to_f / fan_raw_speeds(:max).to_i * 100).round
|
64
|
+
end
|
65
|
+
|
66
|
+
def fan_speed_rpm
|
67
|
+
File.read(fan_file(:input)).strip
|
68
|
+
end
|
69
|
+
|
70
|
+
def memory_clock
|
71
|
+
clock_from_pp_file "#{base_card_dir}/pp_dpm_mclk"
|
72
|
+
end
|
73
|
+
|
74
|
+
def memory_total
|
75
|
+
File.read("#{base_card_dir}/mem_info_vram_total").to_i
|
76
|
+
end
|
77
|
+
|
78
|
+
def name
|
79
|
+
lspci_subsystem.split(': ')[1].strip
|
80
|
+
end
|
81
|
+
|
82
|
+
def power_dpm_state
|
83
|
+
File.read("#{base_card_dir}/power_dpm_state").strip
|
84
|
+
end
|
85
|
+
|
86
|
+
def power_draw
|
87
|
+
power_raw_to_watts File.read(power_avg_file)
|
88
|
+
end
|
89
|
+
|
90
|
+
def power_draw_percent
|
91
|
+
(power_draw.to_f / power_max.to_i * 100).round
|
92
|
+
end
|
93
|
+
|
94
|
+
def power_max
|
95
|
+
@power_max ||= power_raw_to_watts File.read("#{base_hwmon_dir}/power1_cap")
|
96
|
+
end
|
97
|
+
|
98
|
+
def profile_auto
|
99
|
+
sudo_write "#{base_card_dir}/power_dpm_force_performance_level", 'auto'
|
100
|
+
end
|
101
|
+
|
102
|
+
def profile_force=(state)
|
103
|
+
sudo_write "#{base_card_dir}/power_dpm_force_performance_level", 'manual'
|
104
|
+
sudo_write "#{base_card_dir}/pp_power_profile_mode", state
|
105
|
+
end
|
106
|
+
|
107
|
+
def profile_mode
|
108
|
+
File.read("#{base_card_dir}/pp_power_profile_mode").slice(/\w+\s*+\*/).delete('*').strip
|
109
|
+
end
|
110
|
+
|
111
|
+
def profile_summary
|
112
|
+
File.read("#{base_card_dir}/pp_power_profile_mode")
|
113
|
+
end
|
114
|
+
|
115
|
+
def temperature
|
116
|
+
(File.read(temperature_file).to_f / 1000).round(1)
|
117
|
+
end
|
118
|
+
|
119
|
+
def vbios_version
|
120
|
+
@vbios_version ||= File.read("#{base_card_dir}/vbios_version").strip
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def base_card_dir
|
126
|
+
@base_card_dir ||= "#{BASE_FOLDER}/card#{card_num}/device"
|
127
|
+
end
|
128
|
+
|
129
|
+
def base_hwmon_dir
|
130
|
+
@base_hwmon_dir ||= Dir.glob("#{base_card_dir}/hwmon/hwmon*").first
|
131
|
+
end
|
132
|
+
|
133
|
+
def clock_from_pp_file(file)
|
134
|
+
File.read(file).slice(/\w+(?= \*)/)
|
135
|
+
end
|
136
|
+
|
137
|
+
def gpu_pci_id
|
138
|
+
@gpu_pci_id ||= `lspci -v | grep VGA`.split(' ').first
|
139
|
+
end
|
140
|
+
|
141
|
+
def lspci_subsystem
|
142
|
+
@lspci_subsystem ||= `lspci -v -s #{gpu_pci_id} | grep "Subsystem:"`
|
143
|
+
end
|
144
|
+
|
145
|
+
def power_avg_file
|
146
|
+
@power_avg_file ||= Dir.glob("#{base_card_dir}/**/power1_average").first
|
147
|
+
end
|
148
|
+
|
149
|
+
def power_raw_to_watts(raw_string)
|
150
|
+
(raw_string.strip.to_f / 1_000_000).round(2)
|
151
|
+
end
|
152
|
+
|
153
|
+
def temperature_file
|
154
|
+
@temperature_file ||= Dir.glob("#{base_card_dir}/**/temp1_input").first
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amdgpu_fan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin McCormack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A CLI for interacting with the amdgpu Linux driver
|
14
14
|
email: harlemsquirrel@gmail.com
|
@@ -20,9 +20,13 @@ files:
|
|
20
20
|
- README.md
|
21
21
|
- bin/amdgpu_fan
|
22
22
|
- config/environment.rb
|
23
|
-
- lib/
|
24
|
-
- lib/
|
25
|
-
- lib/
|
23
|
+
- lib/amdgpu_fan.rb
|
24
|
+
- lib/amdgpu_fan/cli.rb
|
25
|
+
- lib/amdgpu_fan/connector.rb
|
26
|
+
- lib/amdgpu_fan/mixin/cli_output_format.rb
|
27
|
+
- lib/amdgpu_fan/mixin/fan.rb
|
28
|
+
- lib/amdgpu_fan/mixin/sys_write.rb
|
29
|
+
- lib/amdgpu_fan/service.rb
|
26
30
|
homepage: https://github.com/HarlemSquirrel/amdgpu-fan-rb
|
27
31
|
licenses:
|
28
32
|
- MIT
|
@@ -42,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
46
|
- !ruby/object:Gem::Version
|
43
47
|
version: '0'
|
44
48
|
requirements: []
|
45
|
-
rubygems_version: 3.
|
49
|
+
rubygems_version: 3.1.2
|
46
50
|
signing_key:
|
47
51
|
specification_version: 4
|
48
52
|
summary: A CLI to view and set fan speeds for AMD graphics cards running on the open
|
data/lib/amdgpu_fan_cli.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../config/environment'
|
4
|
-
|
5
|
-
# The main class
|
6
|
-
class AmdgpuFanCli < Thor
|
7
|
-
METER_CHAR = '*'
|
8
|
-
WATCH_FIELD_SEPARATOR = ' | '
|
9
|
-
|
10
|
-
desc 'auto', 'Set fan mode to automatic (requires sudo)'
|
11
|
-
def auto
|
12
|
-
amdgpu_service.fan_mode = :auto
|
13
|
-
puts fan_status
|
14
|
-
end
|
15
|
-
|
16
|
-
desc 'connectors', 'View the status of the display connectors'
|
17
|
-
def connectors
|
18
|
-
amdgpu_service.connectors_status.each do |connector, status|
|
19
|
-
puts "#{connector}: #{status}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
desc 'profile', 'View power profile details.'
|
24
|
-
def profile
|
25
|
-
puts amdgpu_service.profile_summary
|
26
|
-
end
|
27
|
-
|
28
|
-
desc 'profile_auto', 'Set the power profile to automatic mode.'
|
29
|
-
def profile_auto
|
30
|
-
amdgpu_service.profile_auto
|
31
|
-
puts amdgpu_service.profile_summary
|
32
|
-
end
|
33
|
-
|
34
|
-
desc 'profile_force [PROFILE_NUM]', 'Manually set a power profile.'
|
35
|
-
def profile_force(state)
|
36
|
-
amdgpu_service.profile_force = state
|
37
|
-
puts amdgpu_service.profile_summary
|
38
|
-
end
|
39
|
-
|
40
|
-
desc 'set PERCENTAGE', 'Set fan speed to PERCENTAGE (requires sudo)'
|
41
|
-
def set(percentage)
|
42
|
-
return puts 'Invalid percentage' unless (0..100).cover?(percentage.to_i)
|
43
|
-
|
44
|
-
amdgpu_service.set_fan_manual_speed! percent: percentage
|
45
|
-
puts fan_status
|
46
|
-
rescue AmdgpuService::Error
|
47
|
-
puts 'Invalid fan speed provided. The percentage should be between 1 and 100'
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
|
51
|
-
desc 'status [--logo]', 'View device info, current fan speed, and temperature'
|
52
|
-
def status(option = nil)
|
53
|
-
puts radeon_logo if option == '--logo'
|
54
|
-
puts "📺 #{'GPU:'.ljust(7)} #{amdgpu_service.name}",
|
55
|
-
"📄 #{'vBIOS:'.ljust(7)} #{amdgpu_service.vbios_version}",
|
56
|
-
"⏰ #{'Clocks:'.ljust(7)} #{clock_status}",
|
57
|
-
"🌀 #{'Fan:'.ljust(7)} #{fan_status}",
|
58
|
-
"🌞 #{'Temp:'.ljust(7)} #{amdgpu_service.temperature}°C",
|
59
|
-
"⚡ #{'Power:'.ljust(7)} #{amdgpu_service.profile_mode} profile in " \
|
60
|
-
"#{amdgpu_service.power_dpm_state} mode using " \
|
61
|
-
"#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
|
62
|
-
"(#{amdgpu_service.power_draw_percent}%)",
|
63
|
-
"⚖ #{'Load:'.ljust(7)} #{percent_meter amdgpu_service.busy_percent, 20}"
|
64
|
-
end
|
65
|
-
|
66
|
-
desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
|
67
|
-
'refreshed every n seconds'
|
68
|
-
def watch(seconds = 1)
|
69
|
-
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
70
|
-
|
71
|
-
puts "Watching #{amdgpu_service.name} every #{seconds} second(s)...",
|
72
|
-
' <Press Ctrl-C to exit>'
|
73
|
-
|
74
|
-
trap 'SIGINT' do
|
75
|
-
puts "\nAnd now the watch is ended."
|
76
|
-
exit 0
|
77
|
-
end
|
78
|
-
|
79
|
-
loop do
|
80
|
-
time = Time.now
|
81
|
-
puts [time.strftime('%F %T'), summary_clock, summary_fan, summary_load, summary_power,
|
82
|
-
summary_temp].join(WATCH_FIELD_SEPARATOR)
|
83
|
-
|
84
|
-
# It can take a second or two to run the above so we remove them from the wait
|
85
|
-
# here to get a more consistant watch interval.
|
86
|
-
sec_left_to_wait = time.to_i + seconds.to_i - Time.now.to_i
|
87
|
-
sleep sec_left_to_wait if sec_left_to_wait.positive?
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
|
92
|
-
'refreshed every n seconds defaulting to 1 second'
|
93
|
-
def watch_csv(seconds = 1)
|
94
|
-
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
95
|
-
|
96
|
-
puts 'Timestamp, Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm), '\
|
97
|
-
'Load (%),Power (Watts),Temp (°C)'
|
98
|
-
|
99
|
-
trap 'SIGINT' do
|
100
|
-
exit 0
|
101
|
-
end
|
102
|
-
|
103
|
-
loop do
|
104
|
-
puts [Time.now.strftime('%F %T'),
|
105
|
-
amdgpu_service.core_clock,
|
106
|
-
amdgpu_service.memory_clock,
|
107
|
-
amdgpu_service.fan_speed_rpm,
|
108
|
-
amdgpu_service.busy_percent,
|
109
|
-
amdgpu_service.power_draw,
|
110
|
-
amdgpu_service.temperature].join(',')
|
111
|
-
sleep seconds.to_i
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
|
117
|
-
def amdgpu_service
|
118
|
-
@amdgpu_service ||= AmdgpuService.new
|
119
|
-
end
|
120
|
-
|
121
|
-
def clock_status
|
122
|
-
"#{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory"
|
123
|
-
end
|
124
|
-
|
125
|
-
def current_time
|
126
|
-
Time.now.strftime('%F %T')
|
127
|
-
end
|
128
|
-
|
129
|
-
def fan_status
|
130
|
-
"#{amdgpu_service.fan_mode} mode running at " \
|
131
|
-
"#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
|
132
|
-
end
|
133
|
-
|
134
|
-
def percent_meter(percent, length = 10)
|
135
|
-
progress_bar_count = (length * percent.to_f / 100).round
|
136
|
-
percent_string = "#{percent}%".ljust(4)
|
137
|
-
"[#{METER_CHAR * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent_string}"
|
138
|
-
end
|
139
|
-
|
140
|
-
def radeon_logo
|
141
|
-
File.read(File.join(__dir__, '../lib/radeon_r_black_red_100x100.ascii'))
|
142
|
-
end
|
143
|
-
|
144
|
-
def summary_clock
|
145
|
-
"Core: #{amdgpu_service.core_clock.ljust(7)} #{WATCH_FIELD_SEPARATOR}"\
|
146
|
-
"Memory: #{amdgpu_service.memory_clock.ljust(7)}"
|
147
|
-
end
|
148
|
-
|
149
|
-
def summary_fan
|
150
|
-
fan_speed_string = "#{amdgpu_service.fan_speed_rpm} rpm".ljust(8)
|
151
|
-
"Fan: #{fan_speed_string} #{percent_meter(amdgpu_service.fan_speed_percent)}"
|
152
|
-
end
|
153
|
-
|
154
|
-
def summary_load
|
155
|
-
"Load: #{percent_meter amdgpu_service.busy_percent}"
|
156
|
-
end
|
157
|
-
|
158
|
-
def summary_power
|
159
|
-
power_string = "#{amdgpu_service.power_draw} W".ljust(amdgpu_service.power_max.to_s.length + 3)
|
160
|
-
"Power: #{power_string} #{percent_meter amdgpu_service.power_draw_percent}"
|
161
|
-
end
|
162
|
-
|
163
|
-
def summary_temp
|
164
|
-
temp_string = "#{amdgpu_service.temperature}°C".ljust(7)
|
165
|
-
"Temp: #{temp_string}"
|
166
|
-
end
|
167
|
-
end
|
data/lib/amdgpu_service.rb
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
## AmdgpuService
|
4
|
-
#
|
5
|
-
# A service class for reading and interacting with AMD radeon graphics cards
|
6
|
-
# through the amdgpu Linux kernel driver.
|
7
|
-
class AmdgpuService
|
8
|
-
BASE_FOLDER = '/sys/class/drm'
|
9
|
-
FAN_MODES = { '1' => 'manual', '2' => 'auto' }.freeze
|
10
|
-
|
11
|
-
attr_reader :card_num
|
12
|
-
|
13
|
-
class Error < StandardError; end
|
14
|
-
|
15
|
-
def initialize(card_num: 0)
|
16
|
-
@card_num = card_num
|
17
|
-
end
|
18
|
-
|
19
|
-
def busy_percent
|
20
|
-
File.read("#{base_card_folder}/gpu_busy_percent").strip
|
21
|
-
end
|
22
|
-
|
23
|
-
def connectors_status
|
24
|
-
connectors_files.each_with_object({}) do |f, connectors|
|
25
|
-
connectors[f.slice(/(?<=card0-)(\w|-)+/)] = File.read(f).strip
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def core_clock
|
30
|
-
clock_from_pp_file "#{base_card_folder}/pp_dpm_sclk"
|
31
|
-
end
|
32
|
-
|
33
|
-
def fan_mode
|
34
|
-
FAN_MODES[File.read(fan_mode_file).strip] || 'unknown'
|
35
|
-
end
|
36
|
-
|
37
|
-
def fan_mode=(mode)
|
38
|
-
`echo "#{FAN_MODES.key(mode.to_s)}" | sudo tee #{fan_mode_file}`
|
39
|
-
end
|
40
|
-
|
41
|
-
def fan_speed_percent
|
42
|
-
(fan_speed_raw.to_f / fan_speed_raw_max.to_i * 100).round
|
43
|
-
end
|
44
|
-
|
45
|
-
def fan_speed_raw_max
|
46
|
-
@fan_speed_raw_max ||= File.read(Dir.glob("#{base_card_folder}/**/pwm1_max").first).strip
|
47
|
-
end
|
48
|
-
|
49
|
-
def fan_speed_rpm
|
50
|
-
File.read(fan_input_file).strip
|
51
|
-
end
|
52
|
-
|
53
|
-
def memory_clock
|
54
|
-
clock_from_pp_file "#{base_card_folder}/pp_dpm_mclk"
|
55
|
-
end
|
56
|
-
|
57
|
-
def name
|
58
|
-
lspci_subsystem.split(': ')[1].strip
|
59
|
-
end
|
60
|
-
|
61
|
-
def power_dpm_state
|
62
|
-
File.read("#{base_card_folder}/power_dpm_state").strip
|
63
|
-
end
|
64
|
-
|
65
|
-
def power_draw
|
66
|
-
power_raw_to_watts File.read(power_avg_file)
|
67
|
-
end
|
68
|
-
|
69
|
-
def power_draw_percent
|
70
|
-
(power_draw.to_f / power_max.to_i * 100).round
|
71
|
-
end
|
72
|
-
|
73
|
-
def power_max
|
74
|
-
@power_max ||= power_raw_to_watts File.read(power_max_file)
|
75
|
-
end
|
76
|
-
|
77
|
-
def profile_auto
|
78
|
-
`echo "auto" | sudo tee "#{base_card_folder}/power_dpm_force_performance_level"`
|
79
|
-
end
|
80
|
-
|
81
|
-
def profile_force=(state)
|
82
|
-
`echo "manual" | sudo tee "#{base_card_folder}/power_dpm_force_performance_level"`
|
83
|
-
`echo "#{state}" | sudo tee "#{base_card_folder}/pp_power_profile_mode"`
|
84
|
-
end
|
85
|
-
|
86
|
-
def profile_mode
|
87
|
-
File.read("#{base_card_folder}/pp_power_profile_mode").slice(/\w+ \*/).delete('*').strip
|
88
|
-
end
|
89
|
-
|
90
|
-
def profile_summary
|
91
|
-
File.read("#{base_card_folder}/pp_power_profile_mode")
|
92
|
-
end
|
93
|
-
|
94
|
-
def set_fan_manual_speed!(percent: nil, raw: nil)
|
95
|
-
if valid_fan_percent_speed?(percent)
|
96
|
-
new_raw = (percent.to_f / 100 * fan_speed_raw_max.to_i).round
|
97
|
-
elsif valid_fan_raw_speed?(raw)
|
98
|
-
new_raw = raw
|
99
|
-
end
|
100
|
-
|
101
|
-
raise(self.class::Error, 'Invalid fan speed provided') if new_raw.to_s.empty?
|
102
|
-
|
103
|
-
fan_mode = :manual unless fan_mode == 'manual'
|
104
|
-
|
105
|
-
`echo "#{new_raw}" | sudo tee #{fan_power_file}`
|
106
|
-
end
|
107
|
-
|
108
|
-
def temperature
|
109
|
-
(File.read(temperature_file).to_f / 1000).round(1)
|
110
|
-
end
|
111
|
-
|
112
|
-
def vbios_version
|
113
|
-
@vbios_version ||= File.read("#{base_card_folder}/vbios_version").strip
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
def base_card_folder
|
119
|
-
@base_card_folder ||= "#{BASE_FOLDER}/card#{card_num}/device"
|
120
|
-
end
|
121
|
-
|
122
|
-
def clock_from_pp_file(file)
|
123
|
-
File.read(file).slice(/\w+(?= \*)/)
|
124
|
-
end
|
125
|
-
|
126
|
-
def connectors_files
|
127
|
-
@connectors_files ||= Dir["/sys/class/drm/card#{card_num}*/status"].sort
|
128
|
-
end
|
129
|
-
|
130
|
-
def fan_input_file
|
131
|
-
@fan_input_file ||= Dir.glob("#{base_card_folder}/**/fan1_input").first
|
132
|
-
end
|
133
|
-
|
134
|
-
def fan_mode_file
|
135
|
-
@fan_mode_file ||= Dir.glob("#{base_card_folder}/**/pwm1_enable").first
|
136
|
-
end
|
137
|
-
|
138
|
-
def fan_power_file
|
139
|
-
@fan_power_file ||= Dir.glob("#{base_card_folder}/**/pwm1").first
|
140
|
-
end
|
141
|
-
|
142
|
-
def fan_speed_raw
|
143
|
-
File.read(fan_power_file).strip
|
144
|
-
end
|
145
|
-
|
146
|
-
def gpu_pci_id
|
147
|
-
@gpu_pci_id ||= `lspci -v | grep VGA`.split(' ').first
|
148
|
-
end
|
149
|
-
|
150
|
-
def lspci_subsystem
|
151
|
-
@lspci_subsystem ||= `lspci -v -s #{gpu_pci_id} | grep "Subsystem:"`
|
152
|
-
end
|
153
|
-
|
154
|
-
def power_avg_file
|
155
|
-
@power_avg_file ||= Dir.glob("#{base_card_folder}/**/power1_average").first
|
156
|
-
end
|
157
|
-
|
158
|
-
def power_max_file
|
159
|
-
@power_max_file ||= Dir.glob("#{base_card_folder}/**/power1_cap").first
|
160
|
-
end
|
161
|
-
|
162
|
-
def power_raw_to_watts(raw_string)
|
163
|
-
(raw_string.strip.to_f / 1_000_000).round(2)
|
164
|
-
end
|
165
|
-
|
166
|
-
def temperature_file
|
167
|
-
@temperature_file ||= Dir.glob("#{base_card_folder}/**/temp1_input").first
|
168
|
-
end
|
169
|
-
|
170
|
-
def valid_fan_raw_speed?(raw)
|
171
|
-
(1..fan_speed_raw_max.to_i).cover?(raw.to_i)
|
172
|
-
end
|
173
|
-
|
174
|
-
def valid_fan_percent_speed?(percent)
|
175
|
-
(1..100.to_i).cover?(percent.to_i)
|
176
|
-
end
|
177
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
2
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
3
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
4
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
5
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
6
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
7
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
8
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
9
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
10
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
11
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
12
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m.[0m[31m.[0m[31m [0m[31m [0m[31m [0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
13
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m [31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
14
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
15
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
16
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
17
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
18
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
19
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
20
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m [37m [0m [37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
21
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
22
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m [37m [0m[37m [0m [37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
23
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
24
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
25
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
26
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
27
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m [31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
28
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
29
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
30
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
31
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
32
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[37m [0m[37m [0m[37m [0m [37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
33
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[37m [0m[31m [0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
34
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m.[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
35
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
36
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
37
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
38
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
39
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|
40
|
-
[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m[31m'[0m
|