rails_error_dashboard 0.8.3 → 0.9.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 +35 -0
- data/app/controllers/rails_error_dashboard/application_controller.rb +156 -0
- data/app/controllers/rails_error_dashboard/errors_controller.rb +95 -73
- data/app/controllers/rails_error_dashboard/locales_controller.rb +87 -0
- data/app/helpers/rails_error_dashboard/application_helper.rb +20 -14
- data/app/helpers/rails_error_dashboard/backtrace_helper.rb +15 -6
- data/app/helpers/rails_error_dashboard/i18n_helper.rb +154 -0
- data/app/helpers/rails_error_dashboard/mailer_i18n_helper.rb +69 -0
- data/app/helpers/rails_error_dashboard/overview_helper.rb +18 -6
- data/app/helpers/rails_error_dashboard/user_agent_helper.rb +25 -11
- data/app/jobs/rails_error_dashboard/application_job.rb +5 -0
- data/app/jobs/rails_error_dashboard/baseline_alert_job.rb +18 -16
- data/app/jobs/rails_error_dashboard/concerns/localized_job.rb +83 -0
- data/app/jobs/rails_error_dashboard/discord_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/email_error_notification_job.rb +4 -2
- data/app/jobs/rails_error_dashboard/pagerduty_error_notification_job.rb +6 -2
- data/app/jobs/rails_error_dashboard/scheduled_digest_job.rb +8 -3
- data/app/jobs/rails_error_dashboard/slack_error_notification_job.rb +6 -4
- data/app/jobs/rails_error_dashboard/storm_notification_job.rb +26 -8
- data/app/jobs/rails_error_dashboard/webhook_error_notification_job.rb +4 -2
- data/app/mailers/rails_error_dashboard/application_mailer.rb +14 -0
- data/app/mailers/rails_error_dashboard/digest_mailer.rb +18 -2
- data/app/mailers/rails_error_dashboard/error_notification_mailer.rb +19 -2
- data/app/views/layouts/rails_error_dashboard.html.erb +255 -92
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.html.erb +23 -22
- data/app/views/rails_error_dashboard/digest_mailer/digest_summary.text.erb +30 -19
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb +18 -16
- data/app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb +21 -14
- data/app/views/rails_error_dashboard/errors/_ai_help_panel.html.erb +11 -7
- data/app/views/rails_error_dashboard/errors/_breadcrumbs_group.html.erb +45 -38
- data/app/views/rails_error_dashboard/errors/_co_occurring_errors.html.erb +17 -14
- data/app/views/rails_error_dashboard/errors/_discussion.html.erb +27 -9
- data/app/views/rails_error_dashboard/errors/_error_cascades.html.erb +25 -21
- data/app/views/rails_error_dashboard/errors/_error_info.html.erb +25 -22
- data/app/views/rails_error_dashboard/errors/_error_row.html.erb +24 -12
- data/app/views/rails_error_dashboard/errors/_instance_variables.html.erb +12 -11
- data/app/views/rails_error_dashboard/errors/_issue_section.html.erb +19 -13
- data/app/views/rails_error_dashboard/errors/_llm_summary.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_local_variables.html.erb +8 -8
- data/app/views/rails_error_dashboard/errors/_modals.html.erb +60 -52
- data/app/views/rails_error_dashboard/errors/_pattern_insights.html.erb +59 -49
- data/app/views/rails_error_dashboard/errors/_request_context.html.erb +23 -20
- data/app/views/rails_error_dashboard/errors/_show_scripts.html.erb +14 -14
- data/app/views/rails_error_dashboard/errors/_sidebar_metadata.html.erb +118 -93
- data/app/views/rails_error_dashboard/errors/_similar_errors.html.erb +18 -12
- data/app/views/rails_error_dashboard/errors/_source_code.html.erb +20 -5
- data/app/views/rails_error_dashboard/errors/_stats.html.erb +5 -5
- data/app/views/rails_error_dashboard/errors/_timeline.html.erb +7 -7
- data/app/views/rails_error_dashboard/errors/_user_errors_table.html.erb +15 -12
- data/app/views/rails_error_dashboard/errors/actioncable_health_summary.html.erb +25 -25
- data/app/views/rails_error_dashboard/errors/activestorage_health_summary.html.erb +28 -28
- data/app/views/rails_error_dashboard/errors/analytics.html.erb +82 -82
- data/app/views/rails_error_dashboard/errors/cache_health_summary.html.erb +27 -27
- data/app/views/rails_error_dashboard/errors/correlation.html.erb +61 -57
- data/app/views/rails_error_dashboard/errors/database_health_summary.html.erb +64 -65
- data/app/views/rails_error_dashboard/errors/deprecations.html.erb +23 -23
- data/app/views/rails_error_dashboard/errors/diagnostic_dumps.html.erb +48 -36
- data/app/views/rails_error_dashboard/errors/index.html.erb +121 -70
- data/app/views/rails_error_dashboard/errors/job_health_summary.html.erb +30 -30
- data/app/views/rails_error_dashboard/errors/llm_health_summary.html.erb +38 -39
- data/app/views/rails_error_dashboard/errors/n_plus_one_summary.html.erb +28 -25
- data/app/views/rails_error_dashboard/errors/overview.html.erb +45 -39
- data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +45 -44
- data/app/views/rails_error_dashboard/errors/rack_attack_summary.html.erb +39 -28
- data/app/views/rails_error_dashboard/errors/releases.html.erb +46 -47
- data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +48 -44
- data/app/views/rails_error_dashboard/errors/settings.html.erb +122 -112
- data/app/views/rails_error_dashboard/errors/show.html.erb +44 -37
- data/app/views/rails_error_dashboard/errors/storms.html.erb +30 -24
- data/app/views/rails_error_dashboard/errors/swallowed_exceptions.html.erb +26 -26
- data/app/views/rails_error_dashboard/errors/user_impact.html.erb +31 -30
- data/config/locales/de.yml +2007 -0
- data/config/locales/en.yml +2719 -0
- data/config/locales/es.yml +2079 -0
- data/config/locales/fr.yml +2082 -0
- data/config/locales/it.yml +2060 -0
- data/config/locales/ja.yml +1802 -0
- data/config/locales/pl.yml +2108 -0
- data/config/locales/pt-BR.yml +2064 -0
- data/config/locales/ru.yml +2109 -0
- data/config/locales/uk.yml +2106 -0
- data/config/locales/zh-CN.yml +1791 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20260325000001_fix_swallowed_exceptions_index_for_mysql.rb +9 -3
- data/lib/rails_error_dashboard/commands/batch_delete_errors.rb +3 -1
- data/lib/rails_error_dashboard/commands/batch_mute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_resolve_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/batch_unmute_errors.rb +4 -2
- data/lib/rails_error_dashboard/commands/create_issue.rb +5 -3
- data/lib/rails_error_dashboard/commands/link_existing_issue.rb +4 -2
- data/lib/rails_error_dashboard/commands/log_error.rb +1 -1
- data/lib/rails_error_dashboard/configuration.rb +23 -0
- data/lib/rails_error_dashboard/current.rb +56 -0
- data/lib/rails_error_dashboard/i18n_store.rb +293 -0
- data/lib/rails_error_dashboard/private_backend.rb +213 -0
- data/lib/rails_error_dashboard/services/baseline_alert_payload_builder.rb +89 -22
- data/lib/rails_error_dashboard/services/digest_builder.rb +21 -7
- data/lib/rails_error_dashboard/services/discord_payload_builder.rb +27 -15
- data/lib/rails_error_dashboard/services/error_notification_dispatcher.rb +10 -5
- data/lib/rails_error_dashboard/services/localized_time_formatter.rb +117 -0
- data/lib/rails_error_dashboard/services/notification_helpers.rb +87 -4
- data/lib/rails_error_dashboard/services/pagerduty_payload_builder.rb +22 -5
- data/lib/rails_error_dashboard/services/slack_payload_builder.rb +48 -28
- data/lib/rails_error_dashboard/services/storm_protection/gate.rb +2 -1
- data/lib/rails_error_dashboard/services/webhook_payload_builder.rb +15 -1
- data/lib/rails_error_dashboard/translation.rb +39 -0
- data/lib/rails_error_dashboard/version.rb +1 -1
- data/lib/rails_error_dashboard.rb +4 -0
- data/lib/tasks/error_dashboard.rake +5 -1
- metadata +24 -4
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
if value
|
|
6
6
|
%>
|
|
7
7
|
<span class="badge bg-success fs-6">
|
|
8
|
-
<i class="bi bi-check-circle"></i>
|
|
8
|
+
<i class="bi bi-check-circle"></i> <%= red_t("red.settings.values.enabled") %>
|
|
9
9
|
</span>
|
|
10
10
|
<%
|
|
11
11
|
else
|
|
12
12
|
%>
|
|
13
13
|
<span class="badge bg-secondary fs-6">
|
|
14
|
-
<i class="bi bi-x-circle"></i>
|
|
14
|
+
<i class="bi bi-x-circle"></i> <%= red_t("red.settings.values.disabled") %>
|
|
15
15
|
</span>
|
|
16
16
|
<%
|
|
17
17
|
end
|
|
@@ -19,22 +19,24 @@
|
|
|
19
19
|
when :integer
|
|
20
20
|
if value.present?
|
|
21
21
|
%>
|
|
22
|
-
|
|
22
|
+
<%# The unit is a plural key driven by the value, not an English word
|
|
23
|
+
appended to a number — position and form both vary by locale. %>
|
|
24
|
+
<span class="badge bg-info fs-6"><%= unit ? red_tp("red.settings.units.#{unit}", count: value) : value %></span>
|
|
23
25
|
<%
|
|
24
26
|
else
|
|
25
27
|
%>
|
|
26
|
-
<span class="badge bg-secondary fs-6"
|
|
28
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
27
29
|
<%
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
when :float
|
|
31
33
|
if value.present?
|
|
32
34
|
%>
|
|
33
|
-
<span class="badge bg-info fs-6"><%=
|
|
35
|
+
<span class="badge bg-info fs-6"><%= unit ? red_tp("red.settings.units.#{unit}", count: value) : value %></span>
|
|
34
36
|
<%
|
|
35
37
|
else
|
|
36
38
|
%>
|
|
37
|
-
<span class="badge bg-secondary fs-6"
|
|
39
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
38
40
|
<%
|
|
39
41
|
end
|
|
40
42
|
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
<%
|
|
46
48
|
else
|
|
47
49
|
%>
|
|
48
|
-
<span class="badge bg-secondary fs-6"
|
|
50
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
49
51
|
<%
|
|
50
52
|
end
|
|
51
53
|
|
|
@@ -56,7 +58,7 @@
|
|
|
56
58
|
<%
|
|
57
59
|
else
|
|
58
60
|
%>
|
|
59
|
-
<span class="badge bg-secondary fs-6"
|
|
61
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
60
62
|
<%
|
|
61
63
|
end
|
|
62
64
|
|
|
@@ -67,7 +69,7 @@
|
|
|
67
69
|
<%
|
|
68
70
|
else
|
|
69
71
|
%>
|
|
70
|
-
<span class="badge bg-secondary fs-6"
|
|
72
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
71
73
|
<%
|
|
72
74
|
end
|
|
73
75
|
|
|
@@ -78,29 +80,29 @@
|
|
|
78
80
|
<%
|
|
79
81
|
else
|
|
80
82
|
%>
|
|
81
|
-
<span class="badge bg-secondary fs-6"
|
|
83
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
82
84
|
<%
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
when :array
|
|
86
88
|
if value.present? && value.any?
|
|
87
89
|
%>
|
|
88
|
-
<span class="badge bg-info fs-6"><%=
|
|
90
|
+
<span class="badge bg-info fs-6"><%= red_tp("red.settings.values.items", count: value.count) %></span>
|
|
89
91
|
<%
|
|
90
92
|
else
|
|
91
93
|
%>
|
|
92
|
-
<span class="badge bg-secondary fs-6"
|
|
94
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.empty") %></span>
|
|
93
95
|
<%
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
when :hash
|
|
97
99
|
if value.present? && value.any?
|
|
98
100
|
%>
|
|
99
|
-
<span class="badge bg-info fs-6"><%=
|
|
101
|
+
<span class="badge bg-info fs-6"><%= red_tp("red.settings.values.rules", count: value.count) %></span>
|
|
100
102
|
<%
|
|
101
103
|
else
|
|
102
104
|
%>
|
|
103
|
-
<span class="badge bg-secondary fs-6"
|
|
105
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.empty") %></span>
|
|
104
106
|
<%
|
|
105
107
|
end
|
|
106
108
|
|
|
@@ -111,7 +113,7 @@
|
|
|
111
113
|
<%
|
|
112
114
|
else
|
|
113
115
|
%>
|
|
114
|
-
<span class="badge bg-secondary fs-6"
|
|
116
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
115
117
|
<%
|
|
116
118
|
end
|
|
117
119
|
|
|
@@ -128,18 +130,18 @@
|
|
|
128
130
|
<code class="fs-6"><%= effective_value %></code>
|
|
129
131
|
<% if is_auto_detected %>
|
|
130
132
|
<small class="text-success d-block">
|
|
131
|
-
<i class="bi bi-magic"></i>
|
|
133
|
+
<i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
|
|
132
134
|
</small>
|
|
133
135
|
<% else %>
|
|
134
|
-
<small class="text-muted d-block"
|
|
136
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
|
|
135
137
|
<% end %>
|
|
136
138
|
</div>
|
|
137
139
|
<%
|
|
138
140
|
else
|
|
139
141
|
%>
|
|
140
142
|
<div>
|
|
141
|
-
<span class="badge bg-secondary fs-6"
|
|
142
|
-
<small class="text-muted d-block"
|
|
143
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
144
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.rails_app_name_unavailable") %></small>
|
|
143
145
|
</div>
|
|
144
146
|
<%
|
|
145
147
|
end
|
|
@@ -154,11 +156,11 @@
|
|
|
154
156
|
if db_config
|
|
155
157
|
db_name = db_config.database
|
|
156
158
|
status_badge = 'bg-success'
|
|
157
|
-
status_text = "
|
|
159
|
+
status_text = red_t("red.settings.values.separate_db", name: db_config_name)
|
|
158
160
|
else
|
|
159
161
|
db_name = db_config_name
|
|
160
162
|
status_badge = 'bg-warning'
|
|
161
|
-
status_text = "
|
|
163
|
+
status_text = red_t("red.settings.values.configured_but_not_found")
|
|
162
164
|
end
|
|
163
165
|
else
|
|
164
166
|
# Using primary database
|
|
@@ -166,12 +168,12 @@
|
|
|
166
168
|
if db_config
|
|
167
169
|
db_name = db_config.database
|
|
168
170
|
status_badge = 'bg-info'
|
|
169
|
-
status_text = "
|
|
171
|
+
status_text = red_t("red.settings.values.shared_db_primary")
|
|
170
172
|
else
|
|
171
173
|
# Fallback to current connection
|
|
172
|
-
db_name = RailsErrorDashboard::ErrorLog.connection.current_database rescue
|
|
174
|
+
db_name = RailsErrorDashboard::ErrorLog.connection.current_database rescue red_t("red.settings.values.unknown")
|
|
173
175
|
status_badge = 'bg-info'
|
|
174
|
-
status_text = "
|
|
176
|
+
status_text = red_t("red.settings.values.shared_db")
|
|
175
177
|
end
|
|
176
178
|
end
|
|
177
179
|
%>
|
|
@@ -183,8 +185,8 @@
|
|
|
183
185
|
rescue => e
|
|
184
186
|
%>
|
|
185
187
|
<div>
|
|
186
|
-
<span class="badge bg-secondary fs-6"
|
|
187
|
-
<small class="text-muted d-block"
|
|
188
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.unknown") %></span>
|
|
189
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.unable_to_detect") %></small>
|
|
188
190
|
</div>
|
|
189
191
|
<%
|
|
190
192
|
end
|
|
@@ -201,18 +203,18 @@
|
|
|
201
203
|
<code class="fs-6"><%= effective_value %></code>
|
|
202
204
|
<% if is_auto_detected %>
|
|
203
205
|
<small class="text-success d-block">
|
|
204
|
-
<i class="bi bi-magic"></i>
|
|
206
|
+
<i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
|
|
205
207
|
</small>
|
|
206
208
|
<% else %>
|
|
207
|
-
<small class="text-muted d-block"
|
|
209
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
|
|
208
210
|
<% end %>
|
|
209
211
|
</div>
|
|
210
212
|
<%
|
|
211
213
|
else
|
|
212
214
|
%>
|
|
213
215
|
<div>
|
|
214
|
-
<span class="badge bg-secondary fs-6"
|
|
215
|
-
<small class="text-muted d-block"
|
|
216
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_found") %></span>
|
|
217
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.no_user_model") %></small>
|
|
216
218
|
</div>
|
|
217
219
|
<%
|
|
218
220
|
end
|
|
@@ -226,21 +228,23 @@
|
|
|
226
228
|
if effective_value.present?
|
|
227
229
|
%>
|
|
228
230
|
<div>
|
|
229
|
-
<span class="badge <%= is_auto_detected ? 'bg-success' : 'bg-info' %> fs-6"
|
|
231
|
+
<span class="badge <%= is_auto_detected ? 'bg-success' : 'bg-info' %> fs-6"><%# count drives the plural form; the delimited number is what gets displayed,
|
|
232
|
+
so both are passed and the key interpolates %{formatted}. %>
|
|
233
|
+
<%= red_tp("red.settings.values.users", count: effective_value, formatted: number_with_delimiter(effective_value)) %></span>
|
|
230
234
|
<% if is_auto_detected %>
|
|
231
235
|
<small class="text-success d-block">
|
|
232
|
-
<i class="bi bi-magic"></i>
|
|
236
|
+
<i class="bi bi-magic"></i> <%= red_t("red.settings.values.auto_detected") %>
|
|
233
237
|
</small>
|
|
234
238
|
<% else %>
|
|
235
|
-
<small class="text-muted d-block"
|
|
239
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.configured") %></small>
|
|
236
240
|
<% end %>
|
|
237
241
|
</div>
|
|
238
242
|
<%
|
|
239
243
|
else
|
|
240
244
|
%>
|
|
241
245
|
<div>
|
|
242
|
-
<span class="badge bg-secondary fs-6"
|
|
243
|
-
<small class="text-muted d-block"
|
|
246
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_available") %></span>
|
|
247
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.unable_to_query_count") %></small>
|
|
244
248
|
</div>
|
|
245
249
|
<%
|
|
246
250
|
end
|
|
@@ -249,13 +253,13 @@
|
|
|
249
253
|
if value.present?
|
|
250
254
|
%>
|
|
251
255
|
<span class="badge bg-success fs-6">
|
|
252
|
-
<i class="bi bi-check-circle"></i>
|
|
256
|
+
<i class="bi bi-check-circle"></i> <%= red_t("red.settings.values.set") %>
|
|
253
257
|
</span>
|
|
254
258
|
<%
|
|
255
259
|
else
|
|
256
260
|
%>
|
|
257
261
|
<span class="badge bg-warning text-dark fs-6">
|
|
258
|
-
<i class="bi bi-exclamation-triangle"></i>
|
|
262
|
+
<i class="bi bi-exclamation-triangle"></i> <%= red_t("red.settings.values.not_set") %>
|
|
259
263
|
</span>
|
|
260
264
|
<%
|
|
261
265
|
end
|
|
@@ -265,22 +269,22 @@
|
|
|
265
269
|
if value.present?
|
|
266
270
|
%>
|
|
267
271
|
<div>
|
|
268
|
-
<span class="badge bg-warning text-dark fs-6"><%= value
|
|
272
|
+
<span class="badge bg-warning text-dark fs-6"><%= red_tp("red.settings.values.days", count: value) %></span>
|
|
269
273
|
<small class="text-danger d-block">
|
|
270
|
-
<i class="bi bi-exclamation-triangle"></i>
|
|
274
|
+
<i class="bi bi-exclamation-triangle"></i> <%= red_t("red.settings.values.manual_cleanup_required") %>
|
|
271
275
|
</small>
|
|
272
276
|
<small class="text-muted d-block mt-1">
|
|
273
|
-
|
|
277
|
+
<%= red_t("red.settings.values.run_command") %> <code class="small">rails error_dashboard:cleanup_resolved DAYS=<%= value %></code>
|
|
274
278
|
</small>
|
|
275
279
|
</div>
|
|
276
280
|
<%
|
|
277
281
|
else
|
|
278
282
|
%>
|
|
279
283
|
<div>
|
|
280
|
-
<span class="badge bg-success fs-6"><i class="bi bi-infinity"></i>
|
|
281
|
-
<small class="text-muted d-block"
|
|
284
|
+
<span class="badge bg-success fs-6"><i class="bi bi-infinity"></i> <%= red_t("red.settings.values.keep_forever") %></span>
|
|
285
|
+
<small class="text-muted d-block"><%= red_t("red.settings.values.no_automatic_deletion") %></small>
|
|
282
286
|
<small class="text-muted d-block mt-1">
|
|
283
|
-
|
|
287
|
+
<%= red_t("red.settings.values.to_cleanup") %> <code class="small">rails error_dashboard:cleanup_resolved DAYS=90</code>
|
|
284
288
|
</small>
|
|
285
289
|
</div>
|
|
286
290
|
<%
|
|
@@ -294,7 +298,7 @@
|
|
|
294
298
|
<%
|
|
295
299
|
else
|
|
296
300
|
%>
|
|
297
|
-
<span class="badge bg-secondary fs-6"
|
|
301
|
+
<span class="badge bg-secondary fs-6"><%= red_t("red.settings.values.not_set") %></span>
|
|
298
302
|
<%
|
|
299
303
|
end
|
|
300
304
|
end
|