OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/common/extensions/permissions/chrome_permission_message_rules.h
" | 5 #include "chrome/common/extensions/permissions/chrome_permission_message_rules.h
" |
6 | 6 |
7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "chrome/grit/generated_resources.h" | 10 #include "chrome/grit/generated_resources.h" |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 permissions, submessages); | 244 permissions, submessages); |
245 } | 245 } |
246 | 246 |
247 DISALLOW_COPY_AND_ASSIGN(USBDevicesFormatter); | 247 DISALLOW_COPY_AND_ASSIGN(USBDevicesFormatter); |
248 }; | 248 }; |
249 | 249 |
250 } // namespace | 250 } // namespace |
251 | 251 |
252 // Convenience constructors to allow inline initialization of the permission | 252 // Convenience constructors to allow inline initialization of the permission |
253 // ID sets. | 253 // ID sets. |
| 254 // TODO(treib): Once we're allowed to use uniform initialization (and |
| 255 // std::initializer_list), get rid of this helper. |
254 class ChromePermissionMessageRule::PermissionIDSetInitializer | 256 class ChromePermissionMessageRule::PermissionIDSetInitializer |
255 : public std::set<APIPermission::ID> { | 257 : public std::set<APIPermission::ID> { |
256 public: | 258 public: |
257 PermissionIDSetInitializer() {} | 259 template <typename... IDs> |
258 | 260 PermissionIDSetInitializer(IDs... ids) { |
259 // Don't make the constructor explicit to make the usage convenient. | 261 // This effectively calls insert() with each of the ids. |
260 PermissionIDSetInitializer(APIPermission::ID a) { // NOLINT(runtime/explicit) | 262 ExpandHelper(insert(ids)...); |
261 insert(a); | |
262 } | |
263 | |
264 PermissionIDSetInitializer(APIPermission::ID a, APIPermission::ID b) | |
265 : PermissionIDSetInitializer(a) { | |
266 insert(b); | |
267 } | |
268 | |
269 PermissionIDSetInitializer(APIPermission::ID a, | |
270 APIPermission::ID b, | |
271 APIPermission::ID c) | |
272 : PermissionIDSetInitializer(a, b) { | |
273 insert(c); | |
274 } | |
275 | |
276 PermissionIDSetInitializer(APIPermission::ID a, | |
277 APIPermission::ID b, | |
278 APIPermission::ID c, | |
279 APIPermission::ID d) | |
280 : PermissionIDSetInitializer(a, b, c) { | |
281 insert(d); | |
282 } | |
283 | |
284 PermissionIDSetInitializer(APIPermission::ID a, | |
285 APIPermission::ID b, | |
286 APIPermission::ID c, | |
287 APIPermission::ID d, | |
288 APIPermission::ID e) | |
289 : PermissionIDSetInitializer(a, b, c, d) { | |
290 insert(e); | |
291 } | |
292 | |
293 PermissionIDSetInitializer(APIPermission::ID a, | |
294 APIPermission::ID b, | |
295 APIPermission::ID c, | |
296 APIPermission::ID d, | |
297 APIPermission::ID e, | |
298 APIPermission::ID f) | |
299 : PermissionIDSetInitializer(a, b, c, d, e) { | |
300 insert(f); | |
301 } | |
302 | |
303 PermissionIDSetInitializer(APIPermission::ID a, | |
304 APIPermission::ID b, | |
305 APIPermission::ID c, | |
306 APIPermission::ID d, | |
307 APIPermission::ID e, | |
308 APIPermission::ID f, | |
309 APIPermission::ID g) | |
310 : PermissionIDSetInitializer(a, b, c, d, e, f) { | |
311 insert(g); | |
312 } | 263 } |
313 | 264 |
314 virtual ~PermissionIDSetInitializer() {} | 265 virtual ~PermissionIDSetInitializer() {} |
| 266 |
| 267 private: |
| 268 template <typename... Args> |
| 269 void ExpandHelper(Args&&...) {} |
315 }; | 270 }; |
316 | 271 |
317 ChromePermissionMessageRule::ChromePermissionMessageRule( | 272 ChromePermissionMessageRule::ChromePermissionMessageRule( |
318 int message_id, | 273 int message_id, |
319 const PermissionIDSetInitializer& required, | 274 const PermissionIDSetInitializer& required, |
320 const PermissionIDSetInitializer& optional) | 275 const PermissionIDSetInitializer& optional) |
321 : ChromePermissionMessageRule( | 276 : ChromePermissionMessageRule( |
322 new DefaultPermissionMessageFormatter(message_id), | 277 new DefaultPermissionMessageFormatter(message_id), |
323 required, | 278 required, |
324 optional) {} | 279 optional) {} |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 // permission suppresses kTab, be careful to also add kTopSites and kFavicon | 337 // permission suppresses kTab, be careful to also add kTopSites and kFavicon |
383 // to the kHistory absorb list. Ideally, the rules system should be simple | 338 // to the kHistory absorb list. Ideally, the rules system should be simple |
384 // enough that rules like this should not occur; the visibility of the rules | 339 // enough that rules like this should not occur; the visibility of the rules |
385 // system should allow us to design a system that is simple enough to explain | 340 // system should allow us to design a system that is simple enough to explain |
386 // yet powerful enough to encapsulate all the messages we want to display. | 341 // yet powerful enough to encapsulate all the messages we want to display. |
387 ChromePermissionMessageRule rules_arr[] = { | 342 ChromePermissionMessageRule rules_arr[] = { |
388 // Full access permission messages. | 343 // Full access permission messages. |
389 {IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, {APIPermission::kDebugger}, {}}, | 344 {IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, {APIPermission::kDebugger}, {}}, |
390 {IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, | 345 {IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, |
391 {APIPermission::kPlugin}, | 346 {APIPermission::kPlugin}, |
392 // TODO(treib): Add the other IDs implied by kFullAccess/kHostsAll. | 347 {APIPermission::kDeclarativeWebRequest, APIPermission::kFavicon, |
393 {APIPermission::kFullAccess, APIPermission::kHostsAll, | 348 APIPermission::kFullAccess, APIPermission::kHostsAll, |
394 APIPermission::kHostsAllReadOnly, APIPermission::kDeclarativeWebRequest, | 349 APIPermission::kHostsAllReadOnly, APIPermission::kProcesses, |
395 APIPermission::kTopSites, APIPermission::kTab}}, | 350 APIPermission::kTab, APIPermission::kTopSites, |
| 351 APIPermission::kWebNavigation}}, |
396 {IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, | 352 {IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS, |
397 {APIPermission::kFullAccess}, | 353 {APIPermission::kFullAccess}, |
398 // TODO(treib): Add the other IDs implied by kHostsAll. | 354 {APIPermission::kDeclarativeWebRequest, APIPermission::kFavicon, |
399 {APIPermission::kHostsAll, APIPermission::kHostsAllReadOnly, | 355 APIPermission::kHostsAll, APIPermission::kHostsAllReadOnly, |
400 APIPermission::kDeclarativeWebRequest, APIPermission::kTopSites, | 356 APIPermission::kProcesses, APIPermission::kTab, |
401 APIPermission::kTab}}, | 357 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
402 | 358 |
403 // Hosts permission messages. | 359 // Hosts permission messages. |
404 // Full host access already allows DeclarativeWebRequest, reading the list | 360 // Full host access already allows DeclarativeWebRequest, reading the list |
405 // of most frequently visited sites, and tab access. | 361 // of most frequently visited sites, and tab access. |
406 // The warning message for declarativeWebRequest permissions speaks about | 362 // The warning message for declarativeWebRequest permissions speaks about |
407 // blocking parts of pages, which is a subset of what the "<all_urls>" | 363 // blocking parts of pages, which is a subset of what the "<all_urls>" |
408 // access allows. Therefore we display only the "<all_urls>" warning | 364 // access allows. Therefore we display only the "<all_urls>" warning |
409 // message if both permissions are required. | 365 // message if both permissions are required. |
410 {IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS, | 366 {IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS, |
411 {APIPermission::kHostsAll}, | 367 {APIPermission::kHostsAll}, |
412 // TODO(treib): Add kHostReadWrite and kHostReadOnly. | |
413 {APIPermission::kDeclarativeWebRequest, APIPermission::kFavicon, | 368 {APIPermission::kDeclarativeWebRequest, APIPermission::kFavicon, |
414 APIPermission::kHostsAllReadOnly, APIPermission::kProcesses, | 369 APIPermission::kHostsAllReadOnly, APIPermission::kHostReadOnly, |
| 370 APIPermission::kHostReadWrite, APIPermission::kProcesses, |
415 APIPermission::kTab, APIPermission::kTopSites, | 371 APIPermission::kTab, APIPermission::kTopSites, |
416 APIPermission::kWebNavigation}}, | 372 APIPermission::kWebNavigation}}, |
417 {IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY, | 373 {IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY, |
418 {APIPermission::kHostsAllReadOnly}, | 374 {APIPermission::kHostsAllReadOnly}, |
419 // TODO(treib): Add kHostReadOnly. | 375 {APIPermission::kFavicon, APIPermission::kHostReadOnly, |
420 {APIPermission::kFavicon, APIPermission::kProcesses, APIPermission::kTab, | 376 APIPermission::kProcesses, APIPermission::kTab, |
421 APIPermission::kTopSites, APIPermission::kWebNavigation}}, | 377 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
422 | 378 |
| 379 {new CommaSeparatedListFormatter(IDS_EXTENSION_PROMPT_WARNING_1_HOST, |
| 380 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, |
| 381 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, |
| 382 IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST), |
| 383 {APIPermission::kHostReadWrite}, |
| 384 {}}, |
423 {new CommaSeparatedListFormatter( | 385 {new CommaSeparatedListFormatter( |
424 IDS_EXTENSION_PROMPT_WARNING_1_HOST_READ_ONLY, | 386 IDS_EXTENSION_PROMPT_WARNING_1_HOST_READ_ONLY, |
425 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS_READ_ONLY, | 387 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS_READ_ONLY, |
426 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS_READ_ONLY, | 388 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS_READ_ONLY, |
427 IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST_READ_ONLY), | 389 IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST_READ_ONLY), |
428 {APIPermission::kHostReadOnly}, | 390 {APIPermission::kHostReadOnly}, |
429 {}}, | 391 {}}, |
430 {new CommaSeparatedListFormatter(IDS_EXTENSION_PROMPT_WARNING_1_HOST, | |
431 IDS_EXTENSION_PROMPT_WARNING_2_HOSTS, | |
432 IDS_EXTENSION_PROMPT_WARNING_3_HOSTS, | |
433 IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST), | |
434 {APIPermission::kHostReadWrite}, | |
435 {}}, | |
436 | 392 |
437 // History-related permission messages. | 393 // History-related permission messages. |
438 // History already allows reading favicons, tab access and accessing the | 394 // History already allows reading favicons, tab access and accessing the |
439 // list of most frequently visited sites. | 395 // list of most frequently visited sites. |
440 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE_AND_SESSIONS, | 396 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE_AND_SESSIONS, |
441 {APIPermission::kSessions, APIPermission::kHistory}, | 397 {APIPermission::kHistory, APIPermission::kSessions}, |
442 {APIPermission::kFavicon, APIPermission::kProcesses, APIPermission::kTab, | 398 {APIPermission::kFavicon, APIPermission::kProcesses, APIPermission::kTab, |
443 APIPermission::kTopSites, APIPermission::kWebNavigation}}, | 399 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
444 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ_AND_SESSIONS, | 400 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ_AND_SESSIONS, |
445 {APIPermission::kSessions, APIPermission::kTab}, | 401 {APIPermission::kTab, APIPermission::kSessions}, |
446 {APIPermission::kFavicon, APIPermission::kProcesses, | 402 {APIPermission::kFavicon, APIPermission::kProcesses, |
447 APIPermission::kTopSites, APIPermission::kWebNavigation}}, | 403 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
448 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE, | 404 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE, |
449 {APIPermission::kHistory}, | 405 {APIPermission::kHistory}, |
450 {APIPermission::kFavicon, APIPermission::kProcesses, APIPermission::kTab, | 406 {APIPermission::kFavicon, APIPermission::kProcesses, APIPermission::kTab, |
451 APIPermission::kTopSites, APIPermission::kWebNavigation}}, | 407 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
| 408 // Note: kSessions allows reading history from other devices only if kTab |
| 409 // is also present. Therefore, there are no _AND_SESSIONS versions of |
| 410 // the other rules that generate the HISTORY_READ warning. |
452 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, | 411 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, |
453 {APIPermission::kTab}, | 412 {APIPermission::kTab}, |
454 {APIPermission::kFavicon, APIPermission::kProcesses, | 413 {APIPermission::kFavicon, APIPermission::kProcesses, |
455 APIPermission::kTopSites, APIPermission::kWebNavigation}}, | 414 APIPermission::kTopSites, APIPermission::kWebNavigation}}, |
456 // TODO(treib): Should we have _AND_SESSIONS versions of these 2 as well? | |
457 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, | 415 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, |
458 {APIPermission::kProcesses}, | 416 {APIPermission::kProcesses}, |
459 {}}, | 417 {APIPermission::kFavicon, APIPermission::kTopSites, |
| 418 APIPermission::kWebNavigation}}, |
460 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, | 419 {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ, |
461 {APIPermission::kWebNavigation}, | 420 {APIPermission::kWebNavigation}, |
462 {}}, | 421 {APIPermission::kFavicon, APIPermission::kTopSites}}, |
463 {IDS_EXTENSION_PROMPT_WARNING_FAVICON, {APIPermission::kFavicon}, {}}, | 422 {IDS_EXTENSION_PROMPT_WARNING_FAVICON, {APIPermission::kFavicon}, {}}, |
464 {IDS_EXTENSION_PROMPT_WARNING_TOPSITES, {APIPermission::kTopSites}, {}}, | 423 {IDS_EXTENSION_PROMPT_WARNING_TOPSITES, {APIPermission::kTopSites}, {}}, |
| 424 |
465 {IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST, | 425 {IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST, |
466 {APIPermission::kDeclarativeWebRequest}, | 426 {APIPermission::kDeclarativeWebRequest}, |
467 {}}, | 427 {}}, |
468 | 428 |
469 // Messages generated by the sockets permission. | 429 // Messages generated by the sockets permission. |
470 {IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST, | 430 {IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST, |
471 {APIPermission::kSocketAnyHost}, | 431 {APIPermission::kSocketAnyHost}, |
472 // TODO(treib): Add kSocketDomainHosts and kSocketSpecificHosts. | 432 {APIPermission::kSocketDomainHosts, |
473 {}}, | 433 APIPermission::kSocketSpecificHosts}}, |
474 {new SpaceSeparatedListFormatter( | 434 {new SpaceSeparatedListFormatter( |
475 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN, | 435 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN, |
476 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS), | 436 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS), |
477 {APIPermission::kSocketDomainHosts}, | 437 {APIPermission::kSocketDomainHosts}, |
478 {}}, | 438 {}}, |
479 {new SpaceSeparatedListFormatter( | 439 {new SpaceSeparatedListFormatter( |
480 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST, | 440 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST, |
481 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS), | 441 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS), |
482 {APIPermission::kSocketSpecificHosts}, | 442 {APIPermission::kSocketSpecificHosts}, |
483 {}}, | 443 {}}, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 {APIPermission::kAccessibilityFeaturesModify, | 479 {APIPermission::kAccessibilityFeaturesModify, |
520 APIPermission::kAccessibilityFeaturesRead}, | 480 APIPermission::kAccessibilityFeaturesRead}, |
521 {}}, | 481 {}}, |
522 {IDS_EXTENSION_PROMPT_WARNING_ACCESSIBILITY_FEATURES_MODIFY, | 482 {IDS_EXTENSION_PROMPT_WARNING_ACCESSIBILITY_FEATURES_MODIFY, |
523 {APIPermission::kAccessibilityFeaturesModify}, | 483 {APIPermission::kAccessibilityFeaturesModify}, |
524 {}}, | 484 {}}, |
525 {IDS_EXTENSION_PROMPT_WARNING_ACCESSIBILITY_FEATURES_READ, | 485 {IDS_EXTENSION_PROMPT_WARNING_ACCESSIBILITY_FEATURES_READ, |
526 {APIPermission::kAccessibilityFeaturesRead}, | 486 {APIPermission::kAccessibilityFeaturesRead}, |
527 {}}, | 487 {}}, |
528 | 488 |
529 // TODO(sashab): Add the missing combinations of media galleries | 489 // Media galleries permissions. We don't have strings for every possible |
530 // permissions so a valid permission is generated for all combinations. | 490 // combination, e.g. we don't bother with a special string for "write, but |
| 491 // not read" - just show the "read and write" string instead, etc. |
531 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE_DELETE, | 492 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE_DELETE, |
532 {APIPermission::kMediaGalleriesAllGalleriesCopyTo, | 493 {APIPermission::kMediaGalleriesAllGalleriesCopyTo, |
533 APIPermission::kMediaGalleriesAllGalleriesDelete, | 494 APIPermission::kMediaGalleriesAllGalleriesDelete}, |
534 APIPermission::kMediaGalleriesAllGalleriesRead}, | 495 {APIPermission::kMediaGalleriesAllGalleriesRead}}, |
535 {}}, | |
536 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE, | 496 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_WRITE, |
537 {APIPermission::kMediaGalleriesAllGalleriesCopyTo, | 497 {APIPermission::kMediaGalleriesAllGalleriesCopyTo}, |
538 APIPermission::kMediaGalleriesAllGalleriesRead}, | 498 {APIPermission::kMediaGalleriesAllGalleriesRead}}, |
539 {}}, | |
540 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_DELETE, | 499 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ_DELETE, |
541 {APIPermission::kMediaGalleriesAllGalleriesDelete, | 500 {APIPermission::kMediaGalleriesAllGalleriesDelete}, |
542 APIPermission::kMediaGalleriesAllGalleriesRead}, | 501 {APIPermission::kMediaGalleriesAllGalleriesRead}}, |
543 {}}, | |
544 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ, | 502 {IDS_EXTENSION_PROMPT_WARNING_MEDIA_GALLERIES_READ, |
545 {APIPermission::kMediaGalleriesAllGalleriesRead}, | 503 {APIPermission::kMediaGalleriesAllGalleriesRead}, |
546 {}}, | 504 {}}, |
547 | 505 |
548 // The permission string for "fileSystem" is only shown when | 506 // The permission string for "fileSystem" is only shown when |
549 // "write" or "directory" is present. Read-only access is only | 507 // "write" or "directory" is present. Read-only access is only |
550 // granted after the user has been shown a file or directory | 508 // granted after the user has been shown a file or directory |
551 // chooser dialog and selected a file or directory. Selecting | 509 // chooser dialog and selected a file or directory. Selecting |
552 // the file or directory is considered consent to read it. | 510 // the file or directory is considered consent to read it. |
553 {IDS_EXTENSION_PROMPT_WARNING_FILE_SYSTEM_WRITE_DIRECTORY, | 511 {IDS_EXTENSION_PROMPT_WARNING_FILE_SYSTEM_WRITE_DIRECTORY, |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 {IDS_EXTENSION_PROMPT_WARNING_USERS_PRIVATE, | 638 {IDS_EXTENSION_PROMPT_WARNING_USERS_PRIVATE, |
681 {APIPermission::kUsersPrivate}, | 639 {APIPermission::kUsersPrivate}, |
682 {}}, | 640 {}}, |
683 }; | 641 }; |
684 | 642 |
685 return std::vector<ChromePermissionMessageRule>( | 643 return std::vector<ChromePermissionMessageRule>( |
686 rules_arr, rules_arr + arraysize(rules_arr)); | 644 rules_arr, rules_arr + arraysize(rules_arr)); |
687 } | 645 } |
688 | 646 |
689 } // namespace extensions | 647 } // namespace extensions |
OLD | NEW |