bamboozled-gitlab 0.2.9

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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. data/.github/ISSUE_TEMPLATE/question.md +19 -0
  5. data/.github/main.workflow +38 -0
  6. data/.github/pull_request_template.md +27 -0
  7. data/.gitignore +38 -0
  8. data/.rubocop.yml +39 -0
  9. data/.rubocop_todo.yml +305 -0
  10. data/.travis.yml +18 -0
  11. data/CHANGELOG.md +48 -0
  12. data/CONTRIBUTING.md +91 -0
  13. data/Dockerfile +8 -0
  14. data/Gemfile +16 -0
  15. data/Guardfile +21 -0
  16. data/LICENSE +22 -0
  17. data/README.md +170 -0
  18. data/Rakefile +11 -0
  19. data/bamboozled.gemspec +30 -0
  20. data/examples/employees_over_time.rb +53 -0
  21. data/lib/bamboozled.rb +24 -0
  22. data/lib/bamboozled/api/base.rb +101 -0
  23. data/lib/bamboozled/api/employee.rb +118 -0
  24. data/lib/bamboozled/api/field_collection.rb +107 -0
  25. data/lib/bamboozled/api/meta.rb +25 -0
  26. data/lib/bamboozled/api/report.rb +20 -0
  27. data/lib/bamboozled/api/time_off.rb +34 -0
  28. data/lib/bamboozled/api/time_tracking.rb +24 -0
  29. data/lib/bamboozled/base.rb +31 -0
  30. data/lib/bamboozled/errors.rb +33 -0
  31. data/lib/bamboozled/ext/yesno.rb +11 -0
  32. data/lib/bamboozled/version.rb +3 -0
  33. data/logos/bamboozled_logo_black.png +0 -0
  34. data/logos/bamboozled_logo_green.png +0 -0
  35. data/logos/skookum_mark_black.png +0 -0
  36. data/logos/skookum_mark_black.svg +175 -0
  37. data/relnotes/v0.1.0.md +13 -0
  38. data/spec/fixtures/add_employee_details.json +7 -0
  39. data/spec/fixtures/add_employee_response.json +4 -0
  40. data/spec/fixtures/add_employee_xml.yml +8 -0
  41. data/spec/fixtures/all_employees.json +58 -0
  42. data/spec/fixtures/custom_report.json +38 -0
  43. data/spec/fixtures/employee_emails.json +9 -0
  44. data/spec/fixtures/employee_table_details.json +17 -0
  45. data/spec/fixtures/job_info.xml +22 -0
  46. data/spec/fixtures/last_changed.json +28 -0
  47. data/spec/fixtures/meta_fields.json +5 -0
  48. data/spec/fixtures/meta_lists.json +5 -0
  49. data/spec/fixtures/meta_tables.json +5 -0
  50. data/spec/fixtures/meta_users.json +4 -0
  51. data/spec/fixtures/one_employee.json +9 -0
  52. data/spec/fixtures/time_off_estimate.json +23 -0
  53. data/spec/fixtures/time_tracking_add_200_response.json +7 -0
  54. data/spec/fixtures/time_tracking_add_empty_response.json +9 -0
  55. data/spec/fixtures/time_tracking_adjust_200_response.json +7 -0
  56. data/spec/fixtures/time_tracking_adjust_400_response.json +11 -0
  57. data/spec/fixtures/time_tracking_record_200_response.json +9 -0
  58. data/spec/fixtures/time_tracking_record_400_response.json +11 -0
  59. data/spec/fixtures/time_tracking_record_401_response.json +10 -0
  60. data/spec/fixtures/time_tracking_record_404_response.json +8 -0
  61. data/spec/fixtures/update_employee_details.json +7 -0
  62. data/spec/fixtures/update_employee_response.json +3 -0
  63. data/spec/fixtures/update_employee_table.json +8 -0
  64. data/spec/fixtures/update_employee_table_xml.yml +6 -0
  65. data/spec/fixtures/update_employee_xml.yml +8 -0
  66. data/spec/lib/bamboozled/api/base_spec.rb +18 -0
  67. data/spec/lib/bamboozled/api/employee_spec.rb +186 -0
  68. data/spec/lib/bamboozled/api/field_collection_spec.rb +17 -0
  69. data/spec/lib/bamboozled/api/meta_spec.rb +47 -0
  70. data/spec/lib/bamboozled/api/report_spec.rb +17 -0
  71. data/spec/lib/bamboozled/api/time_tracking_spec.rb +123 -0
  72. data/spec/lib/bamboozled/base_spec.rb +26 -0
  73. data/spec/lib/bamboozled_spec.rb +33 -0
  74. data/spec/spec_helper.rb +32 -0
  75. metadata +237 -0
@@ -0,0 +1,34 @@
1
+ module Bamboozled
2
+ module API
3
+ class TimeOff < Base
4
+ def requests(options = {})
5
+ allowed_parameters = %i[id action employeeId start end type status]
6
+ options = options.keep_if { |k, _| allowed_parameters.include? k }
7
+
8
+ # Convert non string dates to strings.
9
+ %i[start end].each do |action|
10
+ if options[action] && !options[action].is_a?(String)
11
+ options[action] = options[action].strftime("%F")
12
+ end
13
+ end
14
+
15
+ # Make sure all statuses are allowed
16
+ if options[:status]
17
+ allowed_statuses = %w[approved denied superceded requested canceled]
18
+ options[:status] = Array(options[:status])
19
+ .keep_if { |v| allowed_statuses.include? v }
20
+ .join(",")
21
+ end
22
+
23
+ request(:get, "time_off/requests?#{URI.encode_www_form(options)}")
24
+ end
25
+
26
+ def whos_out(start_date, end_date = nil)
27
+ start_date = start_date.strftime("%F") unless start_date.is_a?(String)
28
+ end_date = end_date.strftime("%F") unless end_date.nil? ||
29
+ end_date.is_a?(String)
30
+ request(:get, "time_off/whos_out?start=#{start_date}&end=#{end_date}")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ module Bamboozled
2
+ module API
3
+ class TimeTracking < Base
4
+ def record(time_tracking_id)
5
+ request(:get, "timetracking/record/#{time_tracking_id}")
6
+ end
7
+
8
+ def add(time_tracking_details)
9
+ # details = generate_xml(time_tracking_details)
10
+ details = time_tracking_details.to_json
11
+ options = { body: details, headers: { 'Content-Type' => 'application/json' } }
12
+
13
+ request(:post, "timetracking/add/", options)
14
+ end
15
+
16
+ def adjust(time_tracking_id, hours_worked)
17
+ details = { timeTrackingId: time_tracking_id, hoursWorked: hours_worked }.to_json
18
+ options = { body: details, headers: { 'Content-Type' => 'application/json' } }
19
+
20
+ request(:put, "timetracking/adjust", options)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ module Bamboozled
2
+ class Base
3
+ attr_reader :request
4
+
5
+ def initialize(subdomain: nil, api_key: nil, httparty_options: {})
6
+ @subdomain, @api_key = subdomain
7
+ @api_key = api_key
8
+ @httparty_options = httparty_options
9
+ end
10
+
11
+ def employee
12
+ @employee ||= Bamboozled::API::Employee.new(@subdomain, @api_key, @httparty_options)
13
+ end
14
+
15
+ def report
16
+ @report ||= Bamboozled::API::Report.new(@subdomain, @api_key, @httparty_options)
17
+ end
18
+
19
+ def meta
20
+ @meta ||= Bamboozled::API::Meta.new(@subdomain, @api_key, @httparty_options)
21
+ end
22
+
23
+ def time_off
24
+ @time_off ||= Bamboozled::API::TimeOff.new(@subdomain, @api_key, @httparty_options)
25
+ end
26
+
27
+ def time_tracking
28
+ @time_tracking ||= Bamboozled::API::TimeTracking.new(@subdomain, @api_key, @httparty_options)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ module Bamboozled
2
+ class HTTPError < StandardError
3
+ attr_reader :response
4
+ attr_reader :params
5
+ attr_reader :hint
6
+
7
+ def initialize(response, params = {}, hint = nil)
8
+ @response = response
9
+ @params = params
10
+ @hint = hint
11
+ super(response)
12
+ end
13
+
14
+ def to_s
15
+ "#{self.class} : #{response.code} #{response.body}".tap do |msg|
16
+ msg << "\n#{hint}" if hint
17
+ end
18
+ end
19
+ end
20
+
21
+ class BadRequest < HTTPError; end
22
+ class Unauthorized < HTTPError; end
23
+ class AuthenticationFailed < HTTPError; end
24
+ class Forbidden < HTTPError; end
25
+ class NotFound < HTTPError; end
26
+ class NotAcceptable < HTTPError; end
27
+ class Conflict < HTTPError; end
28
+ class LimitExceeded < HTTPError; end
29
+ class InternalServerError < HTTPError; end
30
+ class GatewayError < HTTPError; end
31
+ class ServiceUnavailable < HTTPError; end
32
+ class InformBamboo < HTTPError; end
33
+ end
@@ -0,0 +1,11 @@
1
+ class TrueClass
2
+ def yesno
3
+ "yes"
4
+ end
5
+ end
6
+
7
+ class FalseClass
8
+ def yesno
9
+ "no"
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Bamboozled
2
+ VERSION = "0.2.9".freeze
3
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,175 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ viewBox="0 0 808 808" enable-background="new 0 0 808 808" xml:space="preserve">
6
+ <g enable-background="new ">
7
+ <g>
8
+ <defs>
9
+ <rect id="SVGID_1_" x="120" y="163" width="570" height="486"/>
10
+ </defs>
11
+ <clipPath id="SVGID_2_">
12
+ <use xlink:href="#SVGID_1_" overflow="visible"/>
13
+ </clipPath>
14
+ <g clip-path="url(#SVGID_2_)">
15
+ <defs>
16
+ <rect id="SVGID_3_" width="808" height="808"/>
17
+ </defs>
18
+ <clipPath id="SVGID_4_">
19
+ <use xlink:href="#SVGID_3_" overflow="visible"/>
20
+ </clipPath>
21
+ <g clip-path="url(#SVGID_4_)">
22
+ <defs>
23
+ <path id="SVGID_5_" d="M593.3,648.6H423.4c-2.9,0-5.3-2.4-5.3-5.3l-0.1-269.1c0-1.2,1.4-1.3,1.6-0.1l13.7,91.6
24
+ c4.7,31,27.7,70.5,52.2,89.9l109.9,86.6C600.1,645.7,599.1,648.6,593.3,648.6"/>
25
+ </defs>
26
+ <clipPath id="SVGID_6_">
27
+ <use xlink:href="#SVGID_5_" overflow="visible"/>
28
+ </clipPath>
29
+ <g clip-path="url(#SVGID_6_)">
30
+ <defs>
31
+ <rect id="SVGID_7_" width="808" height="808"/>
32
+ </defs>
33
+ <clipPath id="SVGID_8_">
34
+ <use xlink:href="#SVGID_7_" overflow="visible"/>
35
+ </clipPath>
36
+ <rect x="413.1" y="368.2" clip-path="url(#SVGID_8_)" width="190.3" height="285.4"/>
37
+ </g>
38
+ </g>
39
+ </g>
40
+ <g clip-path="url(#SVGID_2_)">
41
+ <defs>
42
+ <rect id="SVGID_9_" width="808" height="808"/>
43
+ </defs>
44
+ <clipPath id="SVGID_10_">
45
+ <use xlink:href="#SVGID_9_" overflow="visible"/>
46
+ </clipPath>
47
+ <g clip-path="url(#SVGID_10_)">
48
+ <defs>
49
+ <path id="SVGID_11_" d="M388.7,374.1l-13.8,91.6c-4.7,31-27.7,70.5-52.2,89.9l-109.9,86.6c-4.6,3.6-3.6,6.5,2.2,6.5h169.9
50
+ c2.9,0,5.3-2.4,5.3-5.3l0.1-269.1C390.2,373,388.8,372.9,388.7,374.1"/>
51
+ </defs>
52
+ <clipPath id="SVGID_12_">
53
+ <use xlink:href="#SVGID_11_" overflow="visible"/>
54
+ </clipPath>
55
+ <g clip-path="url(#SVGID_12_)">
56
+ <defs>
57
+ <rect id="SVGID_13_" width="808" height="808"/>
58
+ </defs>
59
+ <clipPath id="SVGID_14_">
60
+ <use xlink:href="#SVGID_13_" overflow="visible"/>
61
+ </clipPath>
62
+ <rect x="204.9" y="368.2" clip-path="url(#SVGID_14_)" width="190.3" height="285.4"/>
63
+ </g>
64
+ </g>
65
+ </g>
66
+ <g clip-path="url(#SVGID_2_)">
67
+ <defs>
68
+ <rect id="SVGID_15_" width="808" height="808"/>
69
+ </defs>
70
+ <clipPath id="SVGID_16_">
71
+ <use xlink:href="#SVGID_15_" overflow="visible"/>
72
+ </clipPath>
73
+ <g clip-path="url(#SVGID_16_)">
74
+ <defs>
75
+ <path id="SVGID_17_" d="M686.3,484.6L497,167.7c-1.4-2.3-4.6-4.1-7.3-4.1h-170c-2.6,0-5.9,1.9-7.3,4.1l-189,316.8
76
+ c-2.9,4.9-0.9,7.4,4.5,5.7L283.5,440c12.8-4.1,28-18.9,32.6-31.6l63.8-178.1c1-2.7,4.1-5,7-5h34.8c2.9,0,6.1,2.3,7,5
77
+ l63.8,178.1c4.6,12.7,19.8,27.5,32.6,31.6l156.8,50.4C687.2,492,689.2,489.5,686.3,484.6"/>
78
+ </defs>
79
+ <clipPath id="SVGID_18_">
80
+ <use xlink:href="#SVGID_17_" overflow="visible"/>
81
+ </clipPath>
82
+ <g clip-path="url(#SVGID_18_)">
83
+ <defs>
84
+ <rect id="SVGID_19_" width="808" height="808"/>
85
+ </defs>
86
+ <clipPath id="SVGID_20_">
87
+ <use xlink:href="#SVGID_19_" overflow="visible"/>
88
+ </clipPath>
89
+ <rect x="117.2" y="158.6" clip-path="url(#SVGID_20_)" width="575.4" height="337.2"/>
90
+ </g>
91
+ </g>
92
+ </g>
93
+ <g clip-path="url(#SVGID_2_)">
94
+ <defs>
95
+ <rect id="SVGID_21_" width="808" height="808"/>
96
+ </defs>
97
+ <clipPath id="SVGID_22_">
98
+ <use xlink:href="#SVGID_21_" overflow="visible"/>
99
+ </clipPath>
100
+ <g clip-path="url(#SVGID_22_)">
101
+ <defs>
102
+ <path id="SVGID_23_" d="M347.4,461.4l13.6-90.2c0.2-1.3-1.5-2-2-0.5l-16.7,47.2c-7.4,20.7-29.5,42.1-50.2,48.8l-162.5,52.5
103
+ c-3.1,1-4.2,4-2.4,6.8l59.2,94c1.7,2.7,5.2,3.3,7.7,1.3l111.5-87.8C324.5,518.5,343.7,485.5,347.4,461.4"/>
104
+ </defs>
105
+ <clipPath id="SVGID_24_">
106
+ <use xlink:href="#SVGID_23_" overflow="visible"/>
107
+ </clipPath>
108
+ <g clip-path="url(#SVGID_24_)">
109
+ <defs>
110
+ <rect id="SVGID_25_" width="808" height="808"/>
111
+ </defs>
112
+ <clipPath id="SVGID_26_">
113
+ <use xlink:href="#SVGID_25_" overflow="visible"/>
114
+ </clipPath>
115
+ <rect x="121.2" y="364.9" clip-path="url(#SVGID_26_)" width="244.8" height="262.6"/>
116
+ </g>
117
+ </g>
118
+ </g>
119
+ <g clip-path="url(#SVGID_2_)">
120
+ <defs>
121
+ <rect id="SVGID_27_" width="808" height="808"/>
122
+ </defs>
123
+ <clipPath id="SVGID_28_">
124
+ <use xlink:href="#SVGID_27_" overflow="visible"/>
125
+ </clipPath>
126
+ <g clip-path="url(#SVGID_28_)">
127
+ <defs>
128
+ <path id="SVGID_29_" d="M678.9,519.1l-162.5-52.5c-20.8-6.7-42.8-28.2-50.2-48.8l-16.7-47.2c-0.5-1.5-2.2-0.8-2,0.5l13.5,90.2
129
+ c3.7,24,22.8,57.1,41.9,72l111.5,87.8c2.5,2,6,1.4,7.7-1.3l59.3-94C683,523.2,681.9,520.1,678.9,519.1"/>
130
+ </defs>
131
+ <clipPath id="SVGID_30_">
132
+ <use xlink:href="#SVGID_29_" overflow="visible"/>
133
+ </clipPath>
134
+ <g clip-path="url(#SVGID_30_)">
135
+ <defs>
136
+ <rect id="SVGID_31_" width="808" height="808"/>
137
+ </defs>
138
+ <clipPath id="SVGID_32_">
139
+ <use xlink:href="#SVGID_31_" overflow="visible"/>
140
+ </clipPath>
141
+ <rect x="442.4" y="364.9" clip-path="url(#SVGID_32_)" width="244.7" height="262.6"/>
142
+ </g>
143
+ </g>
144
+ </g>
145
+ <g clip-path="url(#SVGID_2_)">
146
+ <defs>
147
+ <rect id="SVGID_33_" width="808" height="808"/>
148
+ </defs>
149
+ <clipPath id="SVGID_34_">
150
+ <use xlink:href="#SVGID_33_" overflow="visible"/>
151
+ </clipPath>
152
+ <g clip-path="url(#SVGID_34_)">
153
+ <defs>
154
+ <path id="SVGID_35_" d="M590.5,246.3c0-9.2,7.3-16.8,16.2-16.8s16.2,7.6,16.2,16.8s-7.3,16.8-16.2,16.8
155
+ S590.5,255.5,590.5,246.3z M586,246.3c0,11.8,9.3,21.3,20.7,21.3c11.5,0,20.7-9.5,20.7-21.3c0-11.8-9.3-21.3-20.7-21.3
156
+ C595.3,225,586,234.5,586,246.3z M610.2,242c0,3.2-2.9,3.4-6.9,3.4v-6.6C608.4,238.8,610.2,239.1,610.2,242z M616.8,258
157
+ l-6.7-9.5c3-1,4.6-3.8,4.6-6.6c0-4.8-2.8-6.8-11.2-6.8h-4.6V258h4.4v-9.3h1.5l6.7,9.3H616.8z"/>
158
+ </defs>
159
+ <clipPath id="SVGID_36_">
160
+ <use xlink:href="#SVGID_35_" overflow="visible"/>
161
+ </clipPath>
162
+ <g clip-path="url(#SVGID_36_)">
163
+ <defs>
164
+ <rect id="SVGID_37_" width="808" height="808"/>
165
+ </defs>
166
+ <clipPath id="SVGID_38_">
167
+ <use xlink:href="#SVGID_37_" overflow="visible"/>
168
+ </clipPath>
169
+ <rect x="581" y="220" clip-path="url(#SVGID_38_)" fill="#393939" width="51.5" height="52.7"/>
170
+ </g>
171
+ </g>
172
+ </g>
173
+ </g>
174
+ </g>
175
+ </svg>
@@ -0,0 +1,13 @@
1
+ ### New Features
2
+
3
+ * New method `Employee#add` allows client to create new employees. ([@kylefdoherty][])
4
+ * New method `Employee#update` allows client to update new employees. ([@kylefdoherty][])
5
+
6
+ ### Changes
7
+
8
+ ### Bug Fixes
9
+
10
+ * Added missing documentation for `Employee#add`. ([@mjording][])
11
+
12
+ [@kylefdoherty]: https://github.com/kylefdoherty
13
+ [@mjording]: https://github.com/mjording
@@ -0,0 +1,7 @@
1
+ {
2
+ "firstName": "Bruce",
3
+ "lastName": "Wayne",
4
+ "workEmail": "bruce.wayne@gmail.com",
5
+ "jobTitle": "Batman",
6
+ "city": "Gotham"
7
+ }
@@ -0,0 +1,4 @@
1
+ HTTP/1.1 200 OK
2
+ content-type: application/json; charset=utf-8
3
+ date: Tue, 17 Jun 2014 19:25:35 UTC
4
+ location: https://api.bamboohr.com/api/gateway.php/alphasights/v1/employees/44259
@@ -0,0 +1,8 @@
1
+ body:
2
+ <employee><field id='firstName'>Bruce</field><field id='lastName'>Wayne</field><field id='workEmail'>bruce.wayne@gmail.com</field><field id='jobTitle'>Batman</field><field id='city'>Gotham</field></employee>
3
+ headers:
4
+ Accept:
5
+ - application/json
6
+ User-Agent:
7
+ - Bamboozled/0.2.0
8
+
@@ -0,0 +1,58 @@
1
+ HTTP/1.1 200 OK
2
+ content-type: application/json; charset=utf-8
3
+ date: Tue, 17 Jun 2014 19:25:35 UTC
4
+
5
+ {
6
+ "fields": [
7
+ {
8
+ "id": "displayName",
9
+ "type": "text",
10
+ "name": "Display Name"
11
+ },
12
+ {
13
+ "id": "firstName",
14
+ "type": "text",
15
+ "name": "First Name"
16
+ },
17
+ {
18
+ "id": "lastName",
19
+ "type": "text",
20
+ "name": "Last Name"
21
+ },
22
+ {
23
+ "id": "jobTitle",
24
+ "type": "list",
25
+ "name": "Job Title"
26
+ },
27
+ {
28
+ "id": "workPhone",
29
+ "type": "text",
30
+ "name": "Work Phone"
31
+ },
32
+ {
33
+ "id": "workPhoneExtension",
34
+ "type": "text",
35
+ "name": "Work Extension"
36
+ }
37
+ ],
38
+ "employees": [
39
+ {
40
+ "id":123,
41
+ "displayName":"John Doe",
42
+ "firstName":"John",
43
+ "lastName":"Doe",
44
+ "jobTitle":"Customer Service Representative",
45
+ "workPhone":"555-555-5555",
46
+ "workPhoneExtension":null
47
+ },
48
+ {
49
+ "id":124,
50
+ "displayName":"John Doe",
51
+ "firstName":"John",
52
+ "lastName":"Doe",
53
+ "jobTitle":"Customer Service Representative",
54
+ "workPhone":"555-555-5555",
55
+ "workPhoneExtension":null
56
+ }
57
+ ]
58
+ }
@@ -0,0 +1,38 @@
1
+ HTTP/1.1 200 OK
2
+ content-type: application/json; charset=utf-8
3
+ date: Tue, 17 Jun 2014 19:25:35 UTC
4
+
5
+ {
6
+ "employees": [
7
+ {
8
+ "bestEmail": "rachel@example.com",
9
+ "birthday": "05-04",
10
+ "employeeNumber": "100",
11
+ "id": "3"
12
+ },
13
+ {
14
+ "bestEmail": "bob@example.com",
15
+ "birthday": "08-29",
16
+ "employeeNumber": "101",
17
+ "id": "4"
18
+ }
19
+ ],
20
+ "fields": [
21
+ {
22
+ "id": "bestEmail",
23
+ "name": "Email",
24
+ "type": "text"
25
+ },
26
+ {
27
+ "id": "employeeNumber",
28
+ "name": "Employee #",
29
+ "type": "employee_number"
30
+ },
31
+ {
32
+ "id": "birthday",
33
+ "name": "Birthday",
34
+ "type": "text"
35
+ }
36
+ ],
37
+ "title": "Report"
38
+ }