harvested2 5.0.3
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 +7 -0
- data/.document +3 -0
- data/.gitignore +35 -0
- data/.rspec +1 -0
- data/.rubocop.yml +34 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +20 -0
- data/HISTORY.md +118 -0
- data/MIT-LICENSE +21 -0
- data/README.md +66 -0
- data/Rakefile +24 -0
- data/harvested2.gemspec +30 -0
- data/lib/ext/array.rb +52 -0
- data/lib/ext/date.rb +9 -0
- data/lib/ext/hash.rb +17 -0
- data/lib/ext/time.rb +5 -0
- data/lib/harvest/account.rb +13 -0
- data/lib/harvest/api/account.rb +25 -0
- data/lib/harvest/api/base.rb +72 -0
- data/lib/harvest/api/clients.rb +10 -0
- data/lib/harvest/api/company.rb +12 -0
- data/lib/harvest/api/contacts.rb +9 -0
- data/lib/harvest/api/expense_categories.rb +9 -0
- data/lib/harvest/api/expenses.rb +26 -0
- data/lib/harvest/api/invoice_categories.rb +9 -0
- data/lib/harvest/api/invoice_messages.rb +86 -0
- data/lib/harvest/api/invoice_payments.rb +41 -0
- data/lib/harvest/api/invoices.rb +9 -0
- data/lib/harvest/api/projects.rb +9 -0
- data/lib/harvest/api/task_assignments.rb +75 -0
- data/lib/harvest/api/tasks.rb +9 -0
- data/lib/harvest/api/time_entry.rb +19 -0
- data/lib/harvest/api/user_assignments.rb +75 -0
- data/lib/harvest/api/users.rb +10 -0
- data/lib/harvest/base.rb +333 -0
- data/lib/harvest/behavior/activatable.rb +31 -0
- data/lib/harvest/behavior/crud.rb +80 -0
- data/lib/harvest/client.rb +23 -0
- data/lib/harvest/company.rb +8 -0
- data/lib/harvest/contact.rb +20 -0
- data/lib/harvest/credentials.rb +34 -0
- data/lib/harvest/errors.rb +27 -0
- data/lib/harvest/expense.rb +54 -0
- data/lib/harvest/expense_category.rb +10 -0
- data/lib/harvest/hardy_client.rb +80 -0
- data/lib/harvest/invoice.rb +75 -0
- data/lib/harvest/invoice_category.rb +8 -0
- data/lib/harvest/invoice_message.rb +8 -0
- data/lib/harvest/invoice_payment.rb +8 -0
- data/lib/harvest/line_item.rb +21 -0
- data/lib/harvest/model.rb +133 -0
- data/lib/harvest/project.rb +41 -0
- data/lib/harvest/receipt.rb +12 -0
- data/lib/harvest/task.rb +21 -0
- data/lib/harvest/task_assignment.rb +27 -0
- data/lib/harvest/time_entry.rb +57 -0
- data/lib/harvest/timezones.rb +130 -0
- data/lib/harvest/user.rb +58 -0
- data/lib/harvest/user_assignment.rb +27 -0
- data/lib/harvest/version.rb +3 -0
- data/lib/harvested2.rb +96 -0
- data/spec/factories/client.rb +14 -0
- data/spec/factories/contact.rb +8 -0
- data/spec/factories/expense.rb +10 -0
- data/spec/factories/expenses_category.rb +7 -0
- data/spec/factories/invoice.rb +25 -0
- data/spec/factories/invoice_category.rb +5 -0
- data/spec/factories/invoice_message.rb +9 -0
- data/spec/factories/invoice_payment.rb +7 -0
- data/spec/factories/line_item.rb +9 -0
- data/spec/factories/project.rb +15 -0
- data/spec/factories/task.rb +8 -0
- data/spec/factories/task_assignment.rb +8 -0
- data/spec/factories/time_entry.rb +13 -0
- data/spec/factories/user.rb +19 -0
- data/spec/factories/user_assigment.rb +7 -0
- data/spec/functional/clients_spec.rb +105 -0
- data/spec/functional/errors_spec.rb +42 -0
- data/spec/functional/expenses_spec.rb +97 -0
- data/spec/functional/invoice_messages_spec.rb +48 -0
- data/spec/functional/invoice_payments_spec.rb +51 -0
- data/spec/functional/invoice_spec.rb +138 -0
- data/spec/functional/project_spec.rb +76 -0
- data/spec/functional/tasks_spec.rb +119 -0
- data/spec/functional/time_entries_spec.rb +87 -0
- data/spec/functional/users_spec.rb +72 -0
- data/spec/harvest/base_spec.rb +10 -0
- data/spec/harvest/basic_auth_credentials_spec.rb +12 -0
- data/spec/harvest/expense_category_spec.rb +5 -0
- data/spec/harvest/expense_spec.rb +18 -0
- data/spec/harvest/invoice_message_spec.rb +5 -0
- data/spec/harvest/invoice_payment_spec.rb +5 -0
- data/spec/harvest/invoice_spec.rb +5 -0
- data/spec/harvest/oauth_credentials_spec.rb +11 -0
- data/spec/harvest/project_spec.rb +5 -0
- data/spec/harvest/task_assignment_spec.rb +5 -0
- data/spec/harvest/task_spec.rb +5 -0
- data/spec/harvest/time_entry_spec.rb +23 -0
- data/spec/harvest/user_assignment_spec.rb +5 -0
- data/spec/harvest/user_spec.rb +34 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/factory_bot.rb +5 -0
- data/spec/support/harvested_helpers.rb +28 -0
- data/spec/support/json_examples.rb +9 -0
- metadata +238 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
class LineItem < Hashie::Mash
|
|
3
|
+
def initialize(args = {}, _ = nil)
|
|
4
|
+
args = args.stringify_keys
|
|
5
|
+
self.project = args.delete('project') if args['project']
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def project=(project)
|
|
10
|
+
self['project_id'] = project['id']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def active?
|
|
14
|
+
!deactivated
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def line_item_as_json
|
|
18
|
+
{ 'line_item' => { 'id' => line_item_id } }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
module Model
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.send :include, InstanceMethods
|
|
5
|
+
base.send :extend, ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module InstanceMethods
|
|
9
|
+
def to_json(*args)
|
|
10
|
+
as_json(*args).to_json(*args)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def as_json(args = {})
|
|
14
|
+
inner_json = self.to_hash.stringify_keys
|
|
15
|
+
inner_json.delete('cache_version')
|
|
16
|
+
if self.class.skip_json_root?
|
|
17
|
+
inner_json
|
|
18
|
+
else
|
|
19
|
+
{ self.class.json_root => inner_json }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ==(other)
|
|
24
|
+
other.kind_of?(self.class) && id == other.id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def impersonated_user_id
|
|
28
|
+
if respond_to?(:of_user) && respond_to?(:user_id)
|
|
29
|
+
of_user || user_id
|
|
30
|
+
elsif !respond_to?(:of_user) && respond_to?(:user_id)
|
|
31
|
+
user_id
|
|
32
|
+
elsif respond_to?(:of_user)
|
|
33
|
+
of_user
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def json_root
|
|
38
|
+
self.class.json_root
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
# This sets the API path so the API collections can use them in an agnostic way
|
|
44
|
+
# @return [void]
|
|
45
|
+
def api_path(path = nil)
|
|
46
|
+
@_api_path ||= path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def skip_json_root(skip = nil)
|
|
50
|
+
@_skip_json_root ||= skip
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def skip_json_root?
|
|
54
|
+
@_skip_json_root == true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def parse(json)
|
|
58
|
+
parsed = String === json ? JSON.parse(json) : json
|
|
59
|
+
objects = skip_json_root? && parsed[json_root.pluralize] || parsed
|
|
60
|
+
Array.wrap(objects).map { |attrs| new(attrs) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def json_root
|
|
64
|
+
Harvest::Model::Utility.underscore(
|
|
65
|
+
Harvest::Model::Utility.demodulize(to_s))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def to_json(json)
|
|
69
|
+
parsed = String === json ? JSON.parse(json) : json
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def wrap(model_or_attrs)
|
|
73
|
+
case model_or_attrs
|
|
74
|
+
when Hashie::Mash
|
|
75
|
+
model_or_attrs
|
|
76
|
+
when Hash
|
|
77
|
+
new(model_or_attrs)
|
|
78
|
+
else
|
|
79
|
+
model_or_attrs
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def delegate_methods(options)
|
|
84
|
+
raise "no methods given" if options.empty?
|
|
85
|
+
options.each do |source, dest|
|
|
86
|
+
class_eval <<-EOV
|
|
87
|
+
def #{source}
|
|
88
|
+
#{dest}
|
|
89
|
+
end
|
|
90
|
+
EOV
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
module Utility
|
|
96
|
+
class << self
|
|
97
|
+
|
|
98
|
+
# Both methods are shamelessly ripped from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/inflections.rb
|
|
99
|
+
|
|
100
|
+
# Removes the module part from the expression in the string.
|
|
101
|
+
#
|
|
102
|
+
# Examples:
|
|
103
|
+
# "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
|
|
104
|
+
# "Inflections".demodulize
|
|
105
|
+
def demodulize(class_name_in_module)
|
|
106
|
+
class_name_in_module.to_s.gsub(/^.*::/, '')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
|
110
|
+
#
|
|
111
|
+
# Changes '::' to '/' to convert namespaces to paths.
|
|
112
|
+
#
|
|
113
|
+
# Examples:
|
|
114
|
+
# "ActiveRecord".underscore # => "active_record"
|
|
115
|
+
# "ActiveRecord::Errors".underscore # => active_record/errors
|
|
116
|
+
#
|
|
117
|
+
# As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
|
|
118
|
+
# though there are cases where that does not hold:
|
|
119
|
+
#
|
|
120
|
+
# "SSLError".underscore.camelize # => "SslError"
|
|
121
|
+
def underscore(camel_cased_word)
|
|
122
|
+
word = camel_cased_word.to_s.dup
|
|
123
|
+
word.gsub!(/::/, '/')
|
|
124
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
|
125
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
|
126
|
+
word.tr!("-", "_")
|
|
127
|
+
word.downcase!
|
|
128
|
+
word
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
|
|
3
|
+
# The model that contains information about a project
|
|
4
|
+
#
|
|
5
|
+
# == Fields
|
|
6
|
+
# [+id+] (READONLY) the id of the project
|
|
7
|
+
# [+name+] (REQUIRED) the name of the project
|
|
8
|
+
# [+client_id+] (REQUIRED) the client id of the project
|
|
9
|
+
# [+code+] the project code
|
|
10
|
+
# [+notes+] the project notes
|
|
11
|
+
# [+active?+] true|false whether the project is active
|
|
12
|
+
# [+billable?+] true|false where the project is billable
|
|
13
|
+
# [+budget_by+] how the budget is calculated for the project +project|project_cost|task|person|nil+
|
|
14
|
+
# [+budget+] what the budget is for the project (based on budget_by)
|
|
15
|
+
# [+bill_by+] how to bill the project +Tasks|People|Project|nil+
|
|
16
|
+
# [+hourly_rate+] what the hourly rate for the project is based on +bill_by+
|
|
17
|
+
# [+notify_when_over_budget?+] whether the project will send notifications when it goes over budget
|
|
18
|
+
# [+over_budget_notification_percentage+] what percentage of the budget the project has to be before it sends a notification. Based on +notify_when_over_budget?+
|
|
19
|
+
# [+show_budget_to_all?+] whether the project's budget is shown to employees and contractors
|
|
20
|
+
# [+basecamp_id+] (READONLY) the id of the basecamp project associated to the project
|
|
21
|
+
# [+highrise_deal_id+] (READONLY) the id of the highrise deal associated to the project
|
|
22
|
+
# [+active_task_assignments_count+] (READONLY) the number of active task assignments
|
|
23
|
+
# [+created_at+] (READONLY) when the project was created
|
|
24
|
+
# [+updated_at+] (READONLY) when the project was updated
|
|
25
|
+
class Project < Hashie::Mash
|
|
26
|
+
include Harvest::Model
|
|
27
|
+
|
|
28
|
+
skip_json_root true
|
|
29
|
+
api_path '/projects'
|
|
30
|
+
|
|
31
|
+
def initialize(args = {}, _ = nil)
|
|
32
|
+
args = args.stringify_keys
|
|
33
|
+
self.client = args.delete('client') if args['client']
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def client=(client)
|
|
38
|
+
self['client_id'] = client['id']
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
# The model that contains information about a task
|
|
3
|
+
#
|
|
4
|
+
# == Fields
|
|
5
|
+
# [+url+] URL file
|
|
6
|
+
# [+file_name+] file name
|
|
7
|
+
# [+file_size+] size of the image
|
|
8
|
+
# [+content_type+] image/gif
|
|
9
|
+
class Receipt < Hashie::Mash
|
|
10
|
+
include Harvest::Model
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/harvest/task.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
# The model that contains information about a task
|
|
3
|
+
#
|
|
4
|
+
# == Fields
|
|
5
|
+
# [+id+] (READONLY) the id of the task
|
|
6
|
+
# [+name+] (REQUIRED) the name of the task
|
|
7
|
+
# [+billable+] whether the task is billable by default
|
|
8
|
+
# [+deactivated+] whether the task is deactivated
|
|
9
|
+
# [+hourly_rate+] what the default hourly rate for the task is
|
|
10
|
+
# [+default?+] whether to add this task to new projects by default
|
|
11
|
+
class Task < Hashie::Mash
|
|
12
|
+
include Harvest::Model
|
|
13
|
+
|
|
14
|
+
skip_json_root true
|
|
15
|
+
api_path '/tasks'
|
|
16
|
+
|
|
17
|
+
def active?
|
|
18
|
+
!deactivated
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
class TaskAssignment < Hashie::Mash
|
|
3
|
+
include Harvest::Model
|
|
4
|
+
|
|
5
|
+
skip_json_root true
|
|
6
|
+
|
|
7
|
+
def initialize(args = {}, _ = nil)
|
|
8
|
+
args = args.stringify_keys
|
|
9
|
+
self.task = args.delete('task') if args['task']
|
|
10
|
+
self.project = args.delete('project') if args['project']
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def task=(task)
|
|
16
|
+
self['task_id'] = task['id']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def project=(project)
|
|
20
|
+
self['project_id'] = project['id']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def active?
|
|
24
|
+
!deactivated
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
class TimeEntry < Hashie::Mash
|
|
3
|
+
include Harvest::Model
|
|
4
|
+
|
|
5
|
+
skip_json_root true
|
|
6
|
+
api_path '/time_entries'
|
|
7
|
+
|
|
8
|
+
delegate_methods(closed?: :is_closed,
|
|
9
|
+
billed?: :is_billed)
|
|
10
|
+
|
|
11
|
+
def initialize(args = {}, _ = nil)
|
|
12
|
+
args = args.stringify_keys
|
|
13
|
+
self.user = args.delete('user') if args['user']
|
|
14
|
+
self.task = args.delete('task') if args['task']
|
|
15
|
+
self.client = args.delete('client') if args['client']
|
|
16
|
+
self.project = args.delete('project') if args['project']
|
|
17
|
+
self.spent_date = args.delete('spent_date') if args['spent_date']
|
|
18
|
+
self.user_assignment = args.delete('user_assignment') if args['user_assignment']
|
|
19
|
+
self.task_assignment = args.delete('task_assignment') if args['task_assignment']
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def user=(user)
|
|
24
|
+
self['user_id'] = user['id']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def client=(client)
|
|
28
|
+
self['client_id'] = client['id']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def project=(project)
|
|
32
|
+
self['project_id'] = project['id']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def task=(task)
|
|
36
|
+
self['task_id'] = task['id']
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def user_assignment=(user_assignment)
|
|
40
|
+
self['user_assignment_id'] = user_assignment['id']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def task_assignment=(task_assignment)
|
|
44
|
+
self['task_assignment_id'] = task_assignment['id']
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def spent_date=(date)
|
|
48
|
+
self['spent_date'] = Date.parse(date.to_s)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def as_json(args = {})
|
|
52
|
+
super(args).to_hash.stringify_keys.tap do |hash|
|
|
53
|
+
hash.update('spent_date' => (spent_date.nil? ? nil : spent_date.xmlschema))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
module Harvest
|
|
2
|
+
# shamelessly ripped from Rails: http://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
|
|
3
|
+
module Timezones
|
|
4
|
+
MAPPING = {
|
|
5
|
+
'pacific/midway' => 'Midway Island',
|
|
6
|
+
'pacific/pago_pago' => 'Samoa',
|
|
7
|
+
'pacific/honolulu' => 'Hawaii',
|
|
8
|
+
'america/juneau' => 'Alaska',
|
|
9
|
+
'america/los_angeles' => 'Pacific Time (US & Canada)',
|
|
10
|
+
'america/tijuana' => 'Tijuana',
|
|
11
|
+
'america/denver' => 'Mountain Time (US & Canada)',
|
|
12
|
+
'america/phoenix' => 'Arizona',
|
|
13
|
+
'america/chihuahua' => 'Chihuahua',
|
|
14
|
+
'america/mazatlan' => 'Mazatlan',
|
|
15
|
+
'america/chicago' => 'Central Time (US & Canada)',
|
|
16
|
+
'america/regina' => 'Saskatchewan',
|
|
17
|
+
'america/mexico_city' => 'Mexico City',
|
|
18
|
+
'america/monterrey' => 'Monterrey',
|
|
19
|
+
'america/guatemala' => 'Central America',
|
|
20
|
+
'america/new_york' => 'Eastern Time (US & Canada)',
|
|
21
|
+
'america/indiana/indianapolis' => 'Indiana (East)',
|
|
22
|
+
'america/bogota' => 'Bogota',
|
|
23
|
+
'america/lima' => 'Lima',
|
|
24
|
+
'america/halifax' => 'Atlantic Time (Canada)',
|
|
25
|
+
'america/caracas' => 'Caracas',
|
|
26
|
+
'america/la_paz' => 'La Paz',
|
|
27
|
+
'america/santiago' => 'Santiago',
|
|
28
|
+
'america/st_johns' => 'Newfoundland',
|
|
29
|
+
'america/sao_paulo' => 'Brasilia',
|
|
30
|
+
'america/argentina/buenos_aires' => 'Buenos Aires',
|
|
31
|
+
'america/argentina/san_juan' => 'Georgetown',
|
|
32
|
+
'america/godthab' => 'Greenland',
|
|
33
|
+
'atlantic/south_georgia' => 'Mid-Atlantic',
|
|
34
|
+
'atlantic/azores' => 'Azores',
|
|
35
|
+
'atlantic/cape_verde' => 'Cape Verde Is.',
|
|
36
|
+
'europe/dublin' => 'Dublin',
|
|
37
|
+
'europe/lisbon' => 'Lisbon',
|
|
38
|
+
'europe/london' => 'London',
|
|
39
|
+
'africa/casablanca' => 'Casablanca',
|
|
40
|
+
'africa/monrovia' => 'Monrovia',
|
|
41
|
+
'etc/utc' => 'UTC',
|
|
42
|
+
'europe/belgrade' => 'Belgrade',
|
|
43
|
+
'europe/bratislava' => 'Bratislava',
|
|
44
|
+
'europe/budapest' => 'Budapest',
|
|
45
|
+
'europe/ljubljana' => 'Ljubljana',
|
|
46
|
+
'europe/prague' => 'Prague',
|
|
47
|
+
'europe/sarajevo' => 'Sarajevo',
|
|
48
|
+
'europe/skopje' => 'Skopje',
|
|
49
|
+
'europe/warsaw' => 'Warsaw',
|
|
50
|
+
'europe/zagreb' => 'Zagreb',
|
|
51
|
+
'europe/brussels' => 'Brussels',
|
|
52
|
+
'europe/copenhagen' => 'Copenhagen',
|
|
53
|
+
'europe/madrid' => 'Madrid',
|
|
54
|
+
'europe/paris' => 'Paris',
|
|
55
|
+
'europe/amsterdam' => 'Amsterdam',
|
|
56
|
+
'europe/berlin' => 'Berlin',
|
|
57
|
+
'europe/rome' => 'Rome',
|
|
58
|
+
'europe/stockholm' => 'Stockholm',
|
|
59
|
+
'europe/vienna' => 'Vienna',
|
|
60
|
+
'africa/algiers' => 'West Central Africa',
|
|
61
|
+
'europe/bucharest' => 'Bucharest',
|
|
62
|
+
'africa/cairo' => 'Cairo',
|
|
63
|
+
'europe/helsinki' => 'Helsinki',
|
|
64
|
+
'europe/kiev' => 'Kyev',
|
|
65
|
+
'europe/riga' => 'Riga',
|
|
66
|
+
'europe/sofia' => 'Sofia',
|
|
67
|
+
'europe/tallinn' => 'Tallinn',
|
|
68
|
+
'europe/vilnius' => 'Vilnius',
|
|
69
|
+
'europe/athens' => 'Athens',
|
|
70
|
+
'europe/istanbul' => 'Istanbul',
|
|
71
|
+
'europe/minsk' => 'Minsk',
|
|
72
|
+
'asia/jerusalem' => 'Jerusalem',
|
|
73
|
+
'africa/harare' => 'Harare',
|
|
74
|
+
'africa/johannesburg' => 'Pretoria',
|
|
75
|
+
'europe/moscow' => 'Moscow',
|
|
76
|
+
'asia/kuwait' => 'Kuwait',
|
|
77
|
+
'asia/riyadh' => 'Riyadh',
|
|
78
|
+
'africa/nairobi' => 'Nairobi',
|
|
79
|
+
'asia/baghdad' => 'Baghdad',
|
|
80
|
+
'asia/tehran' => 'Tehran',
|
|
81
|
+
'asia/muscat' => 'Muscat',
|
|
82
|
+
'asia/baku' => 'Baku',
|
|
83
|
+
'asia/tbilisi' => 'Tbilisi',
|
|
84
|
+
'asia/yerevan' => 'Yerevan',
|
|
85
|
+
'asia/kabul' => 'Kabul',
|
|
86
|
+
'asia/yekaterinburg' => 'Ekaterinburg',
|
|
87
|
+
'asia/karachi' => 'Karachi',
|
|
88
|
+
'asia/tashkent' => 'Tashkent',
|
|
89
|
+
'asia/kolkata' => 'Kolkata',
|
|
90
|
+
'asia/katmandu' => 'Kathmandu',
|
|
91
|
+
'asia/dhaka' => 'Dhaka',
|
|
92
|
+
'asia/colombo' => 'Sri Jayawardenepura',
|
|
93
|
+
'asia/almaty' => 'Almaty',
|
|
94
|
+
'asia/novosibirsk' => 'Novosibirsk',
|
|
95
|
+
'asia/rangoon' => 'Rangoon',
|
|
96
|
+
'asia/bangkok' => 'Bangkok',
|
|
97
|
+
'asia/jakarta' => 'Jakarta',
|
|
98
|
+
'asia/krasnoyarsk' => 'Krasnoyarsk',
|
|
99
|
+
'asia/shanghai' => 'Beijing',
|
|
100
|
+
'asia/chongqing' => 'Chongqing',
|
|
101
|
+
'asia/hong_kong' => 'Hong Kong',
|
|
102
|
+
'asia/urumqi' => 'Urumqi',
|
|
103
|
+
'asia/kuala_lumpur' => 'Kuala Lumpur',
|
|
104
|
+
'asia/singapore' => 'Singapore',
|
|
105
|
+
'asia/taipei' => 'Taipei',
|
|
106
|
+
'australia/perth' => 'Perth',
|
|
107
|
+
'asia/irkutsk' => 'Irkutsk',
|
|
108
|
+
'asia/ulaanbaatar' => 'Ulaan Bataar',
|
|
109
|
+
'asia/seoul' => 'Seoul',
|
|
110
|
+
'asia/tokyo' => 'Tokyo',
|
|
111
|
+
'asia/yakutsk' => 'Yakutsk',
|
|
112
|
+
'australia/darwin' => 'Darwin',
|
|
113
|
+
'australia/adelaide' => 'Adelaide',
|
|
114
|
+
'australia/melbourne' => 'Melbourne',
|
|
115
|
+
'australia/sydney' => 'Sydney',
|
|
116
|
+
'australia/brisbane' => 'Brisbane',
|
|
117
|
+
'australia/hobart' => 'Hobart',
|
|
118
|
+
'asia/vladivostok' => 'Vladivostok',
|
|
119
|
+
'pacific/guam' => 'Guam',
|
|
120
|
+
'pacific/port_moresby' => 'Port Moresby',
|
|
121
|
+
'asia/magadan' => 'Magadan',
|
|
122
|
+
'pacific/noumea' => 'New Caledonia',
|
|
123
|
+
'pacific/fiji' => 'Fiji',
|
|
124
|
+
'asia/kamchatka' => 'Kamchatka',
|
|
125
|
+
'pacific/majuro' => 'Marshall Is.',
|
|
126
|
+
'pacific/auckland' => 'Auckland',
|
|
127
|
+
'pacific/tongatapu' => "Nuku'alofa"
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
end
|