OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" | 5 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/prefs/pref_service.h" | 8 #include "base/prefs/pref_service.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 using base::UserMetricsAction; | 43 using base::UserMetricsAction; |
44 using content::WebContents; | 44 using content::WebContents; |
45 using content_settings::SettingInfo; | 45 using content_settings::SettingInfo; |
46 using content_settings::SettingSource; | 46 using content_settings::SettingSource; |
47 using content_settings::SETTING_SOURCE_USER; | 47 using content_settings::SETTING_SOURCE_USER; |
48 using content_settings::SETTING_SOURCE_NONE; | 48 using content_settings::SETTING_SOURCE_NONE; |
49 | 49 |
50 namespace { | 50 namespace { |
51 | 51 |
52 const int kAllowButtonIndex = 0; | 52 const int kAllowButtonIndex = 0; |
| 53 const int kAllowOnceButtonIndex = 1; |
53 | 54 |
54 struct ContentSettingsTypeIdEntry { | 55 struct ContentSettingsTypeIdEntry { |
55 ContentSettingsType type; | 56 ContentSettingsType type; |
56 int id; | 57 int id; |
57 }; | 58 }; |
58 | 59 |
59 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries, | 60 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries, |
60 size_t num_entries, | 61 size_t num_entries, |
61 ContentSettingsType type) { | 62 ContentSettingsType type) { |
62 for (size_t i = 0; i < num_entries; ++i) { | 63 for (size_t i = 0; i < num_entries; ++i) { |
(...skipping 25 matching lines...) Expand all Loading... |
88 Delegate* delegate, | 89 Delegate* delegate, |
89 WebContents* web_contents, | 90 WebContents* web_contents, |
90 Profile* profile, | 91 Profile* profile, |
91 ContentSettingsType content_type) | 92 ContentSettingsType content_type) |
92 : ContentSettingBubbleModel(web_contents, profile, content_type), | 93 : ContentSettingBubbleModel(web_contents, profile, content_type), |
93 delegate_(delegate) { | 94 delegate_(delegate) { |
94 // Notifications do not have a bubble. | 95 // Notifications do not have a bubble. |
95 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); | 96 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); |
96 SetTitle(); | 97 SetTitle(); |
97 SetManageLink(); | 98 SetManageLink(); |
| 99 SetLearnMoreLink(); |
98 } | 100 } |
99 | 101 |
100 void ContentSettingTitleAndLinkModel::SetTitle() { | 102 void ContentSettingTitleAndLinkModel::SetTitle() { |
101 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = { | 103 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = { |
102 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE}, | 104 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE}, |
103 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE}, | 105 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE}, |
104 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE}, | 106 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE}, |
105 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE}, | 107 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE}, |
106 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE}, | 108 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE}, |
107 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, | 109 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 }; | 151 }; |
150 set_manage_link(l10n_util::GetStringUTF8( | 152 set_manage_link(l10n_util::GetStringUTF8( |
151 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type()))); | 153 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type()))); |
152 } | 154 } |
153 | 155 |
154 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() { | 156 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() { |
155 if (delegate_) | 157 if (delegate_) |
156 delegate_->ShowContentSettingsPage(content_type()); | 158 delegate_->ShowContentSettingsPage(content_type()); |
157 } | 159 } |
158 | 160 |
| 161 void ContentSettingTitleAndLinkModel::SetLearnMoreLink() { |
| 162 static const ContentSettingsTypeIdEntry kLearnMoreLinkIDs[] = { |
| 163 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_LEARN_MORE}, |
| 164 }; |
| 165 int learn_more_link_id = |
| 166 GetIdForContentType(kLearnMoreLinkIDs, arraysize(kLearnMoreLinkIDs), |
| 167 content_type()); |
| 168 if (learn_more_link_id) |
| 169 set_learn_more_link(l10n_util::GetStringUTF8(learn_more_link_id)); |
| 170 } |
| 171 |
| 172 void ContentSettingTitleAndLinkModel::OnLearnMoreLinkClicked() { |
| 173 if (delegate_) |
| 174 delegate_->ShowLearnMorePage(content_type()); |
| 175 } |
| 176 |
159 class ContentSettingTitleLinkAndCustomModel | 177 class ContentSettingTitleLinkAndCustomModel |
160 : public ContentSettingTitleAndLinkModel { | 178 : public ContentSettingTitleAndLinkModel { |
161 public: | 179 public: |
162 ContentSettingTitleLinkAndCustomModel(Delegate* delegate, | 180 ContentSettingTitleLinkAndCustomModel(Delegate* delegate, |
163 WebContents* web_contents, | 181 WebContents* web_contents, |
164 Profile* profile, | 182 Profile* profile, |
165 ContentSettingsType content_type); | 183 ContentSettingsType content_type); |
166 virtual ~ContentSettingTitleLinkAndCustomModel() {} | 184 virtual ~ContentSettingTitleLinkAndCustomModel() {} |
167 | 185 |
168 private: | 186 private: |
169 void SetCustomLink(); | 187 void SetCustomLink(); |
170 virtual void OnCustomLinkClicked() OVERRIDE {} | 188 virtual void OnCustomLinkClicked() OVERRIDE {} |
171 }; | 189 }; |
172 | 190 |
173 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel( | 191 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel( |
174 Delegate* delegate, | 192 Delegate* delegate, |
175 WebContents* web_contents, | 193 WebContents* web_contents, |
176 Profile* profile, | 194 Profile* profile, |
177 ContentSettingsType content_type) | 195 ContentSettingsType content_type) |
178 : ContentSettingTitleAndLinkModel( | 196 : ContentSettingTitleAndLinkModel( |
179 delegate, web_contents, profile, content_type) { | 197 delegate, web_contents, profile, content_type) { |
180 SetCustomLink(); | 198 SetCustomLink(); |
181 } | 199 } |
182 | 200 |
183 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() { | 201 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() { |
184 static const ContentSettingsTypeIdEntry kCustomIDs[] = { | 202 static const ContentSettingsTypeIdEntry kCustomIDs[] = { |
185 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO}, | 203 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO}, |
186 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL}, | |
187 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON}, | 204 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON}, |
188 }; | 205 }; |
189 int custom_link_id = | 206 int custom_link_id = |
190 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type()); | 207 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type()); |
191 if (custom_link_id) | 208 if (custom_link_id) |
192 set_custom_link(l10n_util::GetStringUTF8(custom_link_id)); | 209 set_custom_link(l10n_util::GetStringUTF8(custom_link_id)); |
193 } | 210 } |
194 | 211 |
195 class ContentSettingSingleRadioGroup | 212 class ContentSettingSingleRadioGroup |
196 : public ContentSettingTitleLinkAndCustomModel { | 213 : public ContentSettingTitleLinkAndCustomModel { |
(...skipping 24 matching lines...) Expand all Loading... |
221 ContentSettingsType content_type) | 238 ContentSettingsType content_type) |
222 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile, | 239 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile, |
223 content_type), | 240 content_type), |
224 block_setting_(CONTENT_SETTING_BLOCK), | 241 block_setting_(CONTENT_SETTING_BLOCK), |
225 selected_item_(0) { | 242 selected_item_(0) { |
226 SetRadioGroup(); | 243 SetRadioGroup(); |
227 } | 244 } |
228 | 245 |
229 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() { | 246 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() { |
230 if (settings_changed()) { | 247 if (settings_changed()) { |
231 ContentSetting setting = | 248 ContentSetting setting; |
232 selected_item_ == kAllowButtonIndex ? | 249 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS) { |
233 CONTENT_SETTING_ALLOW : | 250 if (selected_item_ == kAllowButtonIndex) |
234 block_setting_; | 251 setting = CONTENT_SETTING_ALLOW; |
| 252 else if (selected_item_ == kAllowOnceButtonIndex) |
| 253 setting = CONTENT_SETTING_DEFAULT; |
| 254 else |
| 255 setting = block_setting_; |
| 256 TabSpecificContentSettings::FromWebContents(web_contents())-> |
| 257 set_plugin_bubble_setting(setting); |
| 258 } else { |
| 259 setting = selected_item_ == kAllowButtonIndex ? |
| 260 CONTENT_SETTING_ALLOW : block_setting_; |
| 261 } |
235 AddException(setting); | 262 AddException(setting); |
236 } | 263 } |
237 } | 264 } |
238 | 265 |
239 bool ContentSettingSingleRadioGroup::settings_changed() const { | 266 bool ContentSettingSingleRadioGroup::settings_changed() const { |
240 return selected_item_ != bubble_content().radio_group.default_item; | 267 return selected_item_ != bubble_content().radio_group.default_item; |
241 } | 268 } |
242 | 269 |
243 // Initialize the radio group by setting the appropriate labels for the | 270 // Initialize the radio group by setting the appropriate labels for the |
244 // content type and setting the default value based on the content setting. | 271 // content type and setting the default value based on the content setting. |
245 void ContentSettingSingleRadioGroup::SetRadioGroup() { | 272 void ContentSettingSingleRadioGroup::SetRadioGroup() { |
246 GURL url = web_contents()->GetURL(); | 273 GURL url = web_contents()->GetURL(); |
247 base::string16 display_host; | 274 base::string16 display_host; |
248 net::AppendFormattedHost( | 275 net::AppendFormattedHost( |
249 url, | 276 url, |
250 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), | 277 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 content_type()); | 345 content_type()); |
319 radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? | 346 radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? |
320 l10n_util::GetStringUTF8(resource_id) : | 347 l10n_util::GetStringUTF8(resource_id) : |
321 l10n_util::GetStringFUTF8(resource_id, display_host); | 348 l10n_util::GetStringFUTF8(resource_id, display_host); |
322 } else { | 349 } else { |
323 radio_block_label = l10n_util::GetStringUTF8( | 350 radio_block_label = l10n_util::GetStringUTF8( |
324 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs), | 351 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs), |
325 content_type())); | 352 content_type())); |
326 } | 353 } |
327 | 354 |
| 355 static const ContentSettingsTypeIdEntry kBlockedAllowOnceIDs[] = { |
| 356 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL}, |
| 357 }; |
| 358 |
| 359 std::string radio_allow_once_label; |
| 360 radio_allow_once_label = l10n_util::GetStringUTF8( |
| 361 GetIdForContentType(kBlockedAllowOnceIDs, arraysize(kBlockedAllowOnceIDs), |
| 362 content_type())); |
| 363 |
328 radio_group.radio_items.push_back(radio_allow_label); | 364 radio_group.radio_items.push_back(radio_allow_label); |
| 365 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS) |
| 366 radio_group.radio_items.push_back(radio_allow_once_label); |
329 radio_group.radio_items.push_back(radio_block_label); | 367 radio_group.radio_items.push_back(radio_block_label); |
330 ContentSetting setting; | 368 ContentSetting setting; |
331 SettingSource setting_source = SETTING_SOURCE_NONE; | 369 SettingSource setting_source = SETTING_SOURCE_NONE; |
332 bool setting_is_wildcard = false; | 370 bool setting_is_wildcard = false; |
333 | 371 |
334 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) { | 372 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) { |
335 CookieSettings* cookie_settings = | 373 CookieSettings* cookie_settings = |
336 CookieSettings::Factory::GetForProfile(profile()).get(); | 374 CookieSettings::Factory::GetForProfile(profile()).get(); |
337 setting = cookie_settings->GetCookieSetting( | 375 setting = cookie_settings->GetCookieSetting( |
338 url, url, true, &setting_source); | 376 url, url, true, &setting_source); |
339 } else { | 377 } else { |
340 SettingInfo info; | 378 SettingInfo info; |
341 HostContentSettingsMap* map = profile()->GetHostContentSettingsMap(); | 379 HostContentSettingsMap* map = profile()->GetHostContentSettingsMap(); |
342 scoped_ptr<base::Value> value(map->GetWebsiteSetting( | 380 scoped_ptr<base::Value> value(map->GetWebsiteSetting( |
343 url, url, content_type(), std::string(), &info)); | 381 url, url, content_type(), std::string(), &info)); |
344 setting = content_settings::ValueToContentSetting(value.get()); | 382 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS) |
| 383 setting = content_settings->plugin_bubble_setting(); |
| 384 else |
| 385 setting = content_settings::ValueToContentSetting(value.get()); |
345 setting_source = info.source; | 386 setting_source = info.source; |
346 setting_is_wildcard = | 387 setting_is_wildcard = |
347 info.primary_pattern == ContentSettingsPattern::Wildcard() && | 388 info.primary_pattern == ContentSettingsPattern::Wildcard() && |
348 info.secondary_pattern == ContentSettingsPattern::Wildcard(); | 389 info.secondary_pattern == ContentSettingsPattern::Wildcard(); |
349 } | 390 } |
350 | 391 |
351 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS && | 392 if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS && |
352 setting == CONTENT_SETTING_ALLOW && | 393 setting == CONTENT_SETTING_ALLOW && |
353 setting_is_wildcard) { | 394 setting_is_wildcard) { |
354 // In the corner case of unrecognized plugins (which are now blocked by | 395 // In the corner case of unrecognized plugins (which are now blocked by |
355 // default) we indicate the blocked state in the UI and allow the user to | 396 // default) we indicate the blocked state in the UI and allow the user to |
356 // whitelist. | 397 // whitelist. |
357 radio_group.default_item = 1; | 398 radio_group.default_item = 2; |
| 399 } else if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS && |
| 400 setting == CONTENT_SETTING_DEFAULT) { |
| 401 radio_group.default_item = kAllowOnceButtonIndex; |
358 } else if (setting == CONTENT_SETTING_ALLOW) { | 402 } else if (setting == CONTENT_SETTING_ALLOW) { |
359 radio_group.default_item = kAllowButtonIndex; | 403 radio_group.default_item = kAllowButtonIndex; |
360 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|. | 404 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|. |
361 } else { | 405 } else { |
362 radio_group.default_item = 1; | 406 content_type() == CONTENT_SETTINGS_TYPE_PLUGINS ? |
| 407 radio_group.default_item = 2 : |
| 408 radio_group.default_item = 1; |
363 block_setting_ = setting; | 409 block_setting_ = setting; |
364 } | 410 } |
365 | 411 |
366 set_setting_is_managed(setting_source != SETTING_SOURCE_USER); | 412 set_setting_is_managed(setting_source != SETTING_SOURCE_USER); |
367 if (setting_source != SETTING_SOURCE_USER) { | 413 if (setting_source != SETTING_SOURCE_USER) { |
368 set_radio_group_enabled(false); | 414 set_radio_group_enabled(false); |
369 } else { | 415 } else { |
370 set_radio_group_enabled(true); | 416 set_radio_group_enabled(true); |
371 } | 417 } |
372 selected_item_ = radio_group.default_item; | 418 selected_item_ = radio_group.default_item; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 Delegate* delegate, | 494 Delegate* delegate, |
449 WebContents* web_contents, | 495 WebContents* web_contents, |
450 Profile* profile, | 496 Profile* profile, |
451 ContentSettingsType content_type) | 497 ContentSettingsType content_type) |
452 : ContentSettingSingleRadioGroup( | 498 : ContentSettingSingleRadioGroup( |
453 delegate, web_contents, profile, content_type) { | 499 delegate, web_contents, profile, content_type) { |
454 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS); | 500 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS); |
455 // Disable the "Run all plugins this time" link if the setting is managed and | 501 // Disable the "Run all plugins this time" link if the setting is managed and |
456 // can't be controlled by the user or if the user already clicked on the link | 502 // can't be controlled by the user or if the user already clicked on the link |
457 // and ran all plugins. | 503 // and ran all plugins. |
| 504 // TODO(radhikabhar) this might not be needed if we switch to the new UI |
458 set_custom_link_enabled(!setting_is_managed() && | 505 set_custom_link_enabled(!setting_is_managed() && |
459 web_contents && | 506 web_contents && |
460 TabSpecificContentSettings::FromWebContents( | 507 TabSpecificContentSettings::FromWebContents( |
461 web_contents)->load_plugins_link_enabled()); | 508 web_contents)->load_plugins_link_enabled()); |
462 } | 509 } |
463 | 510 |
464 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() { | 511 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() { |
465 if (settings_changed()) { | 512 if (settings_changed()) { |
466 // If the user elected to allow all plugins then run plugins at this time. | 513 // If the user elected to allow all plugins then run plugins at this time. |
467 if (selected_item() == kAllowButtonIndex) | 514 if (selected_item() == kAllowButtonIndex |
468 OnCustomLinkClicked(); | 515 || selected_item() == kAllowOnceButtonIndex) |
| 516 OnCustomLinkClicked(); |
469 } | 517 } |
470 } | 518 } |
471 | 519 |
472 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() { | 520 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() { |
473 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble")); | 521 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble")); |
474 DCHECK(web_contents()); | 522 DCHECK(web_contents()); |
475 #if defined(ENABLE_PLUGINS) | 523 #if defined(ENABLE_PLUGINS) |
476 // TODO(bauerb): We should send the identifiers of blocked plug-ins here. | 524 // TODO(bauerb): We should send the identifiers of blocked plug-ins here. |
477 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( | 525 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( |
478 web_contents(), true, std::string()); | 526 web_contents(), true, std::string()); |
(...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { | 1354 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
1307 DCHECK_EQ(web_contents_, | 1355 DCHECK_EQ(web_contents_, |
1308 content::Source<WebContents>(source).ptr()); | 1356 content::Source<WebContents>(source).ptr()); |
1309 web_contents_ = NULL; | 1357 web_contents_ = NULL; |
1310 } else { | 1358 } else { |
1311 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); | 1359 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); |
1312 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); | 1360 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); |
1313 profile_ = NULL; | 1361 profile_ = NULL; |
1314 } | 1362 } |
1315 } | 1363 } |
OLD | NEW |