harvested2 5.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|