calendar-assistant 0.9.0 → 0.14.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/Gemfile +2 -1
- data/README.md +44 -22
- data/Rakefile +37 -6
- data/bin/calendar-assistant +3 -1
- data/lib/calendar_assistant.rb +14 -16
- data/lib/calendar_assistant/available_block.rb +1 -1
- data/lib/calendar_assistant/calendar_assistant.rb +21 -25
- data/lib/calendar_assistant/cli.rb +10 -10
- data/lib/calendar_assistant/cli/authorizer.rb +14 -14
- data/lib/calendar_assistant/cli/command_service.rb +2 -2
- data/lib/calendar_assistant/cli/commands.rb +47 -40
- data/lib/calendar_assistant/cli/config.rb +16 -17
- data/lib/calendar_assistant/cli/event_presenter.rb +2 -2
- data/lib/calendar_assistant/cli/event_set_presenter.rb +3 -3
- data/lib/calendar_assistant/cli/helpers.rb +7 -8
- data/lib/calendar_assistant/cli/linter_event_presenter.rb +3 -3
- data/lib/calendar_assistant/cli/linter_event_set_presenter.rb +4 -4
- data/lib/calendar_assistant/cli/printer.rb +15 -15
- data/lib/calendar_assistant/config.rb +11 -11
- data/lib/calendar_assistant/config/token_store.rb +4 -4
- data/lib/calendar_assistant/date_helpers.rb +1 -2
- data/lib/calendar_assistant/event.rb +54 -50
- data/lib/calendar_assistant/event_repository.rb +14 -15
- data/lib/calendar_assistant/event_repository_factory.rb +1 -1
- data/lib/calendar_assistant/event_set.rb +14 -14
- data/lib/calendar_assistant/extensions/google_apis_extensions.rb +1 -1
- data/lib/calendar_assistant/extensions/launchy_extensions.rb +7 -4
- data/lib/calendar_assistant/has_duration.rb +4 -5
- data/lib/calendar_assistant/lint_event_repository.rb +3 -3
- data/lib/calendar_assistant/location_config_validator.rb +3 -3
- data/lib/calendar_assistant/location_event_repository.rb +7 -8
- data/lib/calendar_assistant/predicate_collection.rb +1 -2
- data/lib/calendar_assistant/scheduler.rb +4 -5
- data/lib/calendar_assistant/string_helpers.rb +1 -1
- data/lib/calendar_assistant/version.rb +1 -1
- metadata +38 -30
@@ -7,7 +7,7 @@ class CalendarAssistant
|
|
7
7
|
@options = options.dup
|
8
8
|
@options[CalendarAssistant::Config::Keys::Options::CONTEXT] ||= context.to_s
|
9
9
|
|
10
|
-
@config
|
10
|
+
@config = CalendarAssistant::CLI::Config.new(options: @options)
|
11
11
|
@authorizer = {}
|
12
12
|
@out = CalendarAssistant::CLI::Printer.new
|
13
13
|
end
|
@@ -34,4 +34,4 @@ class CalendarAssistant
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
end
|
37
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
class CalendarAssistant
|
2
2
|
module CLI
|
3
3
|
class Commands < Thor
|
4
|
+
HISTORY_FILE_PATH = File.join (ENV["CA_HOME"] || ENV["HOME"]), ".calendar-assistant.history"
|
5
|
+
|
4
6
|
def self.will_create_a_service
|
5
7
|
option CalendarAssistant::Config::Keys::Settings::PROFILE,
|
6
8
|
type: :string,
|
@@ -11,7 +13,7 @@ class CalendarAssistant
|
|
11
13
|
type: :string,
|
12
14
|
banner: "FILENAME",
|
13
15
|
desc: "Load events from a local file instead of Google Calendar",
|
14
|
-
aliases: [
|
16
|
+
aliases: ["-l"]
|
15
17
|
end
|
16
18
|
|
17
19
|
def self.has_events
|
@@ -19,12 +21,12 @@ class CalendarAssistant
|
|
19
21
|
type: :string,
|
20
22
|
desc: "Event properties that must be true (see README)",
|
21
23
|
banner: "PROPERTY1[,PROPERTY2[,...]]",
|
22
|
-
aliases: [
|
24
|
+
aliases: ["-b"]
|
23
25
|
option CalendarAssistant::Config::Keys::Options::MUST_NOT_BE,
|
24
26
|
type: :string,
|
25
27
|
desc: "Event properties that must be false (see README)",
|
26
28
|
banner: "PROPERTY1[,PROPERTY2[,...]]",
|
27
|
-
aliases: [
|
29
|
+
aliases: ["-n"]
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.has_multiple_calendars
|
@@ -50,7 +52,6 @@ class CalendarAssistant
|
|
50
52
|
default: CalendarAssistant::Config::DEFAULT_SETTINGS[CalendarAssistant::Config::Keys::Options::FORMATTING],
|
51
53
|
aliases: "-f"
|
52
54
|
|
53
|
-
|
54
55
|
desc "version",
|
55
56
|
"Display the version of calendar-assistant"
|
56
57
|
|
@@ -59,28 +60,26 @@ class CalendarAssistant
|
|
59
60
|
command_service.out.puts CalendarAssistant::VERSION
|
60
61
|
end
|
61
62
|
|
62
|
-
|
63
63
|
desc "config",
|
64
64
|
"Dump your configuration parameters (merge of defaults and overrides from #{CalendarAssistant::CLI::Config::CONFIG_FILE_PATH})"
|
65
65
|
|
66
66
|
def config
|
67
67
|
return if handle_help_args
|
68
68
|
settings = CalendarAssistant::CLI::Config.new.settings
|
69
|
-
command_service.out.puts TOML::Generator.new({CalendarAssistant::Config::Keys::SETTINGS => settings}).body
|
69
|
+
command_service.out.puts TOML::Generator.new({ CalendarAssistant::Config::Keys::SETTINGS => settings }).body
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
72
|
desc "setup",
|
74
73
|
"Link your local calendar-assistant installation to a Google API Client"
|
75
74
|
long_desc <<~EOD
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
This command will walk you through setting up a Google Cloud
|
76
|
+
Project, enabling the Google Calendar API, and saving the
|
77
|
+
credentials necessary to access the API on behalf of users.
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
If you already have downloaded client credentials, you don't
|
80
|
+
need to run this command. Instead, rename the downloaded JSON
|
81
|
+
file to `#{CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH}`
|
82
|
+
EOD
|
84
83
|
|
85
84
|
def setup
|
86
85
|
# TODO ugh see #34 for advice on how to clean this up
|
@@ -94,14 +93,14 @@ class CalendarAssistant
|
|
94
93
|
command_service.out.launch "https://developers.google.com/calendar/quickstart/ruby"
|
95
94
|
sleep 1
|
96
95
|
command_service.out.puts <<~EOT
|
97
|
-
|
96
|
+
Please click on "ENABLE THE GOOGLE CALENDAR API" and either create a new project or select an existing project.
|
98
97
|
|
99
|
-
|
98
|
+
(If you create a new project, name it something like "yourname-calendar-assistant" so you remember why it exists.)
|
100
99
|
|
101
|
-
|
100
|
+
Then click "DOWNLOAD CLIENT CONFIGURATION" to download the credentials to local disk.
|
102
101
|
|
103
|
-
|
104
|
-
|
102
|
+
Finally, paste the contents of the downloaded file here (it should be a complete JSON object):
|
103
|
+
EOT
|
105
104
|
|
106
105
|
json = command_service.out.prompt "Paste JSON here"
|
107
106
|
File.open(CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH, "w") do |f|
|
@@ -112,22 +111,21 @@ class CalendarAssistant
|
|
112
111
|
command_service.out.puts "\nOK! Your next step is to run `calendar-assistant authorize`."
|
113
112
|
end
|
114
113
|
|
115
|
-
|
116
114
|
desc "authorize PROFILE_NAME",
|
117
115
|
"create (or validate) a profile named NAME with calendar access"
|
118
116
|
long_desc <<~EOD
|
119
|
-
|
120
|
-
|
117
|
+
Create and authorize a named profile (e.g., "work", "home",
|
118
|
+
"flastname@company.tld") to access your calendar.
|
121
119
|
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
When setting up a profile, you'll be asked to visit a URL to
|
121
|
+
authenticate, grant authorization, and generate and persist an
|
122
|
+
access token.
|
125
123
|
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
In order for this to work, you'll need to have set up your API client
|
125
|
+
credentials. Run `calendar-assistant help setup` for instructions.
|
126
|
+
EOD
|
129
127
|
|
130
|
-
def authorize
|
128
|
+
def authorize(profile_name = nil)
|
131
129
|
return if handle_help_args
|
132
130
|
return help! if profile_name.nil?
|
133
131
|
|
@@ -142,7 +140,8 @@ class CalendarAssistant
|
|
142
140
|
has_multiple_calendars
|
143
141
|
|
144
142
|
has_events
|
145
|
-
|
143
|
+
|
144
|
+
def lint(datespec = "today")
|
146
145
|
calendar_assistant(datespec) do |ca, date, out|
|
147
146
|
event_set = ca.lint_events date
|
148
147
|
out.print_events ca, event_set, presenter_class: CalendarAssistant::CLI::LinterEventSetPresenter
|
@@ -159,14 +158,14 @@ class CalendarAssistant
|
|
159
158
|
has_multiple_calendars
|
160
159
|
|
161
160
|
has_events
|
162
|
-
|
161
|
+
|
162
|
+
def show(datespec = "today")
|
163
163
|
calendar_assistant(datespec) do |ca, date, out|
|
164
164
|
event_set = ca.find_events date
|
165
165
|
out.print_events ca, event_set
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
-
|
170
169
|
desc "join [TIME]",
|
171
170
|
"Open the URL for a video call attached to your meeting at time TIME (default 'now')"
|
172
171
|
option CalendarAssistant::Config::Keys::Options::JOIN,
|
@@ -175,7 +174,8 @@ class CalendarAssistant
|
|
175
174
|
will_create_a_service
|
176
175
|
|
177
176
|
has_events
|
178
|
-
|
177
|
+
|
178
|
+
def join(timespec = "now")
|
179
179
|
return if handle_help_args
|
180
180
|
set_formatting
|
181
181
|
ca = CalendarAssistant.new command_service.config, service: command_service.service
|
@@ -191,20 +191,19 @@ class CalendarAssistant
|
|
191
191
|
end
|
192
192
|
end
|
193
193
|
|
194
|
-
|
195
194
|
desc "location [DATE | DATERANGE]",
|
196
195
|
"Show your location for a date or range of dates (default 'today')"
|
197
196
|
will_create_a_service
|
198
197
|
|
199
198
|
has_events
|
200
|
-
|
199
|
+
|
200
|
+
def location(datespec = "today")
|
201
201
|
calendar_assistant(datespec) do |ca, date, out|
|
202
202
|
event_set = ca.find_location_events date
|
203
203
|
out.print_events ca, event_set
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
|
208
207
|
desc "location-set LOCATION [DATE | DATERANGE]",
|
209
208
|
"Set your location to LOCATION for a date or range of dates (default 'today')"
|
210
209
|
option CalendarAssistant::Config::Keys::Options::FORCE,
|
@@ -217,7 +216,8 @@ class CalendarAssistant
|
|
217
216
|
will_create_a_service
|
218
217
|
has_events
|
219
218
|
has_multiple_calendars
|
220
|
-
|
219
|
+
|
220
|
+
def location_set(location = nil, datespec = "today")
|
221
221
|
return help! if location.nil?
|
222
222
|
|
223
223
|
calendar_assistant(datespec) do |ca, date, out|
|
@@ -226,7 +226,6 @@ class CalendarAssistant
|
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
229
|
-
|
230
229
|
desc "availability [DATE | DATERANGE | TIMERANGE]",
|
231
230
|
"Show your availability for a date or range of dates (default 'today')"
|
232
231
|
option CalendarAssistant::Config::Keys::Settings::MEETING_LENGTH,
|
@@ -250,13 +249,21 @@ class CalendarAssistant
|
|
250
249
|
has_multiple_calendars
|
251
250
|
will_create_a_service
|
252
251
|
has_events
|
253
|
-
|
252
|
+
|
253
|
+
def availability(datespec = "today")
|
254
254
|
calendar_assistant(datespec) do |ca, date, out|
|
255
255
|
event_set = ca.availability date
|
256
256
|
out.print_available_blocks ca, event_set
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
|
+
desc "interactive", "interactive console for calendar assistant"
|
261
|
+
def interactive
|
262
|
+
return if handle_help_args
|
263
|
+
require "thor_repl"
|
264
|
+
ThorRepl.start(CalendarAssistant::CLI::Commands, history_file_path: HISTORY_FILE_PATH, prompt: Rainbow("calendar-asssistant> ").bright)
|
265
|
+
end
|
266
|
+
|
260
267
|
private
|
261
268
|
|
262
269
|
def set_formatting
|
@@ -267,7 +274,7 @@ class CalendarAssistant
|
|
267
274
|
@command_service ||= CommandService.new(context: current_command_chain.first, options: options)
|
268
275
|
end
|
269
276
|
|
270
|
-
def calendar_assistant
|
277
|
+
def calendar_assistant(datespec = "today", &block)
|
271
278
|
return if handle_help_args
|
272
279
|
set_formatting
|
273
280
|
command_service.calendar_assistant(datespec, &block)
|
@@ -1,31 +1,30 @@
|
|
1
1
|
class CalendarAssistant
|
2
2
|
module CLI
|
3
3
|
class Config < CalendarAssistant::Config
|
4
|
-
class TomlParseFailure < CalendarAssistant::BaseException
|
4
|
+
class TomlParseFailure < CalendarAssistant::BaseException
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
|
+
class NoConfigFileToPersist < CalendarAssistant::BaseException
|
7
8
|
end
|
8
9
|
|
9
|
-
CONFIG_FILE_PATH = File.join (ENV[
|
10
|
+
CONFIG_FILE_PATH = File.join (ENV["CA_HOME"] || ENV["HOME"]), ".calendar-assistant"
|
10
11
|
attr_reader :config_file_path
|
11
12
|
|
12
|
-
def initialize
|
13
|
+
def initialize(options: {},
|
13
14
|
config_file_path: CONFIG_FILE_PATH,
|
14
|
-
defaults: DEFAULT_SETTINGS
|
15
|
-
|
16
|
-
|
15
|
+
defaults: DEFAULT_SETTINGS)
|
17
16
|
@config_file_path = config_file_path
|
18
17
|
|
19
18
|
user_config = if File.exist? config_file_path
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
begin
|
20
|
+
FileUtils.chmod 0600, config_file_path
|
21
|
+
TOML.load_file config_file_path
|
22
|
+
rescue Exception => e
|
23
|
+
raise TomlParseFailure, "could not parse TOML file '#{config_file_path}': #{e}"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Hash.new
|
27
|
+
end
|
29
28
|
super(options: options, defaults: defaults, user_config: user_config)
|
30
29
|
end
|
31
30
|
|
@@ -48,4 +47,4 @@ class CalendarAssistant
|
|
48
47
|
end
|
49
48
|
end
|
50
49
|
end
|
51
|
-
end
|
50
|
+
end
|
@@ -46,7 +46,7 @@ class CalendarAssistant
|
|
46
46
|
date_ansi_codes << :bright if current?
|
47
47
|
date_ansi_codes << :faint if past?
|
48
48
|
|
49
|
-
date_ansi_codes.inject(rainbow.wrap(date)) {|text, ansi| text.send ansi}
|
49
|
+
date_ansi_codes.inject(rainbow.wrap(date)) { |text, ansi| text.send ansi }
|
50
50
|
end
|
51
51
|
|
52
52
|
def event_date
|
@@ -60,7 +60,7 @@ class CalendarAssistant
|
|
60
60
|
end
|
61
61
|
else
|
62
62
|
if start_date == end_date
|
63
|
-
sprintf("%s - %s", start.date_time.strftime("%Y-%m-%d %H:%M"),
|
63
|
+
sprintf("%s - %s", start.date_time.strftime("%Y-%m-%d %H:%M"), __getobj__.end.date_time.strftime("%H:%M"))
|
64
64
|
else
|
65
65
|
sprintf("%s - %s", start.date_time.strftime("%Y-%m-%d %H:%M"), __getobj__.end.date_time.strftime("%Y-%m-%d %H:%M"))
|
66
66
|
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
class CalendarAssistant
|
3
3
|
module CLI
|
4
4
|
module Helpers
|
5
|
-
class ChronicParseException < CalendarAssistant::BaseException
|
5
|
+
class ChronicParseException < CalendarAssistant::BaseException
|
6
6
|
end
|
7
7
|
|
8
|
-
def self.parse_datespec
|
8
|
+
def self.parse_datespec(userspec)
|
9
9
|
start_userspec, end_userspec = userspec.split(/ ?\.\.\.? ?/)
|
10
10
|
|
11
11
|
if end_userspec.nil?
|
@@ -25,21 +25,20 @@ class CalendarAssistant
|
|
25
25
|
|
26
26
|
def self.now
|
27
27
|
CalendarAssistant::Event.new(
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
Google::Apis::CalendarV3::Event.new(start: Google::Apis::CalendarV3::EventDateTime.new(date_time: Time.now),
|
29
|
+
end: Google::Apis::CalendarV3::EventDateTime.new(date_time: Time.now),
|
30
|
+
summary: Rainbow(" now ").inverse.faint)
|
31
31
|
)
|
32
32
|
end
|
33
33
|
|
34
|
-
def self.find_av_uri
|
34
|
+
def self.find_av_uri(ca, timespec)
|
35
35
|
time = Chronic.parse timespec
|
36
36
|
range = time..(time + 5.minutes)
|
37
37
|
event_set = ca.find_events range
|
38
38
|
|
39
39
|
[CalendarAssistant::Event::Response::ACCEPTED,
|
40
40
|
CalendarAssistant::Event::Response::TENTATIVE,
|
41
|
-
CalendarAssistant::Event::Response::NEEDS_ACTION
|
42
|
-
].each do |response|
|
41
|
+
CalendarAssistant::Event::Response::NEEDS_ACTION].each do |response|
|
43
42
|
event_set.events.reverse.select do |event|
|
44
43
|
event.response_status == response
|
45
44
|
end.each do |event|
|
@@ -12,12 +12,12 @@ class CalendarAssistant
|
|
12
12
|
s += rainbow.wrap(sprintf(" | %s", view_summary)).bold
|
13
13
|
s += event_attributes unless private?
|
14
14
|
s = rainbow.wrap(Rainbow.uncolor(s)).faint.strike if declined?
|
15
|
-
s += "\n #{
|
15
|
+
s += "\n #{" " * (date_length + 2)}attendees: #{attendees}"
|
16
16
|
s
|
17
17
|
end
|
18
18
|
|
19
19
|
def attendees
|
20
|
-
if required_other_attendees
|
20
|
+
if required_other_attendees.length > SUMMARY_THRESHOLD
|
21
21
|
summary_attendee_list
|
22
22
|
else
|
23
23
|
detailed_attendee_list
|
@@ -43,7 +43,7 @@ class CalendarAssistant
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def required_other_attendees
|
46
|
-
@required_other_attendees ||= (other_human_attendees || []).select {|a| !a.optional }
|
46
|
+
@required_other_attendees ||= (other_human_attendees || []).select { |a| !a.optional }
|
47
47
|
end
|
48
48
|
|
49
49
|
def response_emoji(response_status)
|
@@ -7,9 +7,9 @@ class CalendarAssistant
|
|
7
7
|
|
8
8
|
def title
|
9
9
|
rainbow.wrap(<<~OUT)
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
#{event_repository.calendar.id}
|
11
|
+
- looking for events that need attention
|
12
|
+
- all times in #{event_repository.calendar.time_zone}
|
13
13
|
OUT
|
14
14
|
end
|
15
15
|
|
@@ -20,4 +20,4 @@ class CalendarAssistant
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
-
end
|
23
|
+
end
|
@@ -2,16 +2,15 @@
|
|
2
2
|
class CalendarAssistant
|
3
3
|
module CLI
|
4
4
|
class Printer
|
5
|
-
class LaunchUrlException < CalendarAssistant::BaseException
|
6
|
-
|
5
|
+
class LaunchUrlException < CalendarAssistant::BaseException; end
|
7
6
|
|
8
7
|
attr_reader :io
|
9
8
|
|
10
|
-
def initialize
|
9
|
+
def initialize(io = STDOUT)
|
11
10
|
@io = io
|
12
11
|
end
|
13
12
|
|
14
|
-
def launch
|
13
|
+
def launch(url)
|
15
14
|
begin
|
16
15
|
Launchy.open(url)
|
17
16
|
rescue Exception => e
|
@@ -19,11 +18,11 @@ class CalendarAssistant
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
|
-
def puts
|
21
|
+
def puts(*args)
|
23
22
|
io.puts(*args)
|
24
23
|
end
|
25
24
|
|
26
|
-
def prompt
|
25
|
+
def prompt(query, default = nil)
|
27
26
|
loop do
|
28
27
|
message = query
|
29
28
|
message += " [#{default}]" if default
|
@@ -39,27 +38,28 @@ class CalendarAssistant
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
def print_events
|
41
|
+
def print_events(ca, event_set, presenter_class: CLI::EventSetPresenter)
|
43
42
|
puts presenter_class.new(event_set, config: ca.config).to_s
|
44
43
|
puts
|
45
44
|
end
|
46
45
|
|
47
|
-
def print_available_blocks
|
48
|
-
ers = ca.config.calendar_ids.map {|calendar_id| ca.event_repository calendar_id}
|
49
|
-
time_zones = ers.map {|er| er.calendar.time_zone}.uniq
|
46
|
+
def print_available_blocks(ca, event_set, omit_title: false)
|
47
|
+
ers = ca.config.calendar_ids.map { |calendar_id| ca.event_repository calendar_id }
|
48
|
+
time_zones = ers.map { |er| er.calendar.time_zone }.uniq
|
50
49
|
|
51
50
|
unless omit_title
|
52
|
-
puts Rainbow(ers.map {|er| er.calendar.id}.join(", ")).italic
|
51
|
+
puts Rainbow(ers.map { |er| er.calendar.id }.join(", ")).italic
|
53
52
|
puts Rainbow(sprintf("- looking for blocks at least %s long",
|
54
53
|
ChronicDuration.output(
|
55
|
-
|
56
|
-
|
54
|
+
ChronicDuration.parse(
|
55
|
+
ca.config.setting(Config::Keys::Settings::MEETING_LENGTH)
|
56
|
+
)
|
57
|
+
))).italic
|
57
58
|
time_zones.each do |time_zone|
|
58
59
|
puts Rainbow(sprintf("- between %s and %s in %s",
|
59
60
|
ca.config.setting(Config::Keys::Settings::START_OF_DAY),
|
60
61
|
ca.config.setting(Config::Keys::Settings::END_OF_DAY),
|
61
|
-
time_zone
|
62
|
-
)).italic
|
62
|
+
time_zone)).italic
|
63
63
|
end
|
64
64
|
puts
|
65
65
|
end
|