summaryrefslogtreecommitdiff
path: root/kolab.org/www/drupal-7.26/modules/simpletest
diff options
context:
space:
mode:
Diffstat (limited to 'kolab.org/www/drupal-7.26/modules/simpletest')
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/drupal_web_test_case.php3706
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/README.txt4
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css80
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css80
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css30
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css6
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css40
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css69
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css4
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css69
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css29
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css6
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css39
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import1.css6
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import2.css5
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/html-1.txt1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/html-2.html1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/image-1.pngbin0 -> 39325 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/image-2.jpgbin0 -> 1831 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.gifbin0 -> 183 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.jpgbin0 -> 1901 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.pngbin0 -> 125 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-1.txt3
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-2.script3
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/php-1.txt3
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/php-2.php2
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/sql-1.txt1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/files/sql-2.sql1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php18
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.api.php60
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.css89
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.info62
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.install182
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.js104
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.module626
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.pages.inc513
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/simpletest.test746
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/actions.test126
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.install11
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.module95
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax.test530
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.module502
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.module79
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/batch.test403
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.callbacks.inc141
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.module513
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/bootstrap.test543
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/cache.test437
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common.test2787
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.css2
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.info14
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.module276
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.print.css2
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test_cron_helper.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test_cron_helper.module17
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test_info.txt9
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/database_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/database_test.install221
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/database_test.module241
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/database_test.test4111
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_cache_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_cache_test.module27
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_cache_test_dependency.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_cache_test_dependency.module17
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_crud_hook_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_crud_hook_test.module251
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_crud_hook_test.test338
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_query.test1681
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_query_access_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/entity_query_access_test.module54
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/error.test116
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/error_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/error_test.module65
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/file.test2782
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/file_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/file_test.module461
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/filetransfer.test168
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/filter_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/filter_test.module64
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/form.test1867
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/form_test.file.inc48
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/form_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/form_test.module1857
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/graph.test195
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/http.php32
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/https.php31
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/image.test507
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/image_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/image_test.module138
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/lock.test57
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/mail.test461
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/menu.test1740
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/menu_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/menu_test.module563
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/module.test304
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/module_test.file.inc13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/module_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/module_test.install42
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/module_test.module131
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/pager.test159
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/password.test60
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/path.test381
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/path_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/path_test.module23
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php18
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php18
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/psr_0_test/psr_0_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/psr_0_test/psr_0_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/registry.test142
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/requirements1_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/requirements1_test.install21
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/requirements1_test.module7
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/requirements2_test.info14
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/requirements2_test.module7
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/schema.test384
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/session.test530
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/session_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/session_test.module192
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system.base.css6
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_dependencies_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_dependencies_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_core_version_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_core_version_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info14
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_module_version_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_incompatible_module_version_test.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/system_test.module407
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/tablesort.test166
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/taxonomy_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/taxonomy_test.install34
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/taxonomy_test.module111
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/theme.test502
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/theme_test.inc15
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/theme_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/theme_test.module134
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/theme_test.template_test.tpl.php2
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/themes/test_theme/template.php19
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/themes/test_theme/test_theme.info24
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/unicode.test305
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update.test115
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_script_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_script_test.install45
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_script_test.module18
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_1.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_1.install53
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_1.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_2.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_2.install53
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_2.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_3.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_3.install24
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/update_test_3.module1
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.bare.database.php8131
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.comments.database.php40
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.duplicate-permission.database.php8
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.filled.database.php20384
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.forum.database.php274
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.locale.database.php276
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.menu.database.php202
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php34
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.translatable.database.php125
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.trigger.database.php82
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.upload.database.php449
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.user-no-password-token.database.php10
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-6.user-password-token.database.php55
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php149
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gzbin0 -> 39843 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gzbin0 -> 77424 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.field.database.php16
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gzbin0 -> 41805 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gzbin0 -> 97603 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/drupal-7.trigger.database.php28
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/update.aggregator.test47
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/update.field.test61
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/update.trigger.test37
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/update.user.test35
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.comment.test32
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.filter.test55
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.forum.test64
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.locale.test143
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.menu.test83
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.node.test148
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.poll.test66
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.taxonomy.test201
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.test737
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.translatable.test51
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.trigger.test39
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.upload.test83
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/upgrade/upgrade.user.test92
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/url_alter_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/url_alter_test.install12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/url_alter_test.module71
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/xmlrpc.test244
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/xmlrpc_test.info12
-rw-r--r--kolab.org/www/drupal-7.26/modules/simpletest/tests/xmlrpc_test.module111
210 files changed, 68812 insertions, 0 deletions
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/drupal_web_test_case.php b/kolab.org/www/drupal-7.26/modules/simpletest/drupal_web_test_case.php
new file mode 100644
index 0000000..6d0e59a
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/drupal_web_test_case.php
@@ -0,0 +1,3706 @@
+<?php
+
+/**
+ * Global variable that holds information about the tests being run.
+ *
+ * An array, with the following keys:
+ * - 'test_run_id': the ID of the test being run, in the form 'simpletest_%"
+ * - 'in_child_site': TRUE if the current request is a cURL request from
+ * the parent site.
+ *
+ * @var array
+ */
+global $drupal_test_info;
+
+/**
+ * Base class for Drupal tests.
+ *
+ * Do not extend this class, use one of the subclasses in this file.
+ */
+abstract class DrupalTestCase {
+ /**
+ * The test run ID.
+ *
+ * @var string
+ */
+ protected $testId;
+
+ /**
+ * The database prefix of this test run.
+ *
+ * @var string
+ */
+ protected $databasePrefix = NULL;
+
+ /**
+ * The original file directory, before it was changed for testing purposes.
+ *
+ * @var string
+ */
+ protected $originalFileDirectory = NULL;
+
+ /**
+ * Time limit for the test.
+ */
+ protected $timeLimit = 500;
+
+ /**
+ * Current results of this test case.
+ *
+ * @var Array
+ */
+ public $results = array(
+ '#pass' => 0,
+ '#fail' => 0,
+ '#exception' => 0,
+ '#debug' => 0,
+ );
+
+ /**
+ * Assertions thrown in that test case.
+ *
+ * @var Array
+ */
+ protected $assertions = array();
+
+ /**
+ * This class is skipped when looking for the source of an assertion.
+ *
+ * When displaying which function an assert comes from, it's not too useful
+ * to see "drupalWebTestCase->drupalLogin()', we would like to see the test
+ * that called it. So we need to skip the classes defining these helper
+ * methods.
+ */
+ protected $skipClasses = array(__CLASS__ => TRUE);
+
+ /**
+ * Flag to indicate whether the test has been set up.
+ *
+ * The setUp() method isolates the test from the parent Drupal site by
+ * creating a random prefix for the database and setting up a clean file
+ * storage directory. The tearDown() method then cleans up this test
+ * environment. We must ensure that setUp() has been run. Otherwise,
+ * tearDown() will act on the parent Drupal site rather than the test
+ * environment, destroying live data.
+ */
+ protected $setup = FALSE;
+
+ protected $setupDatabasePrefix = FALSE;
+
+ protected $setupEnvironment = FALSE;
+
+ /**
+ * Constructor for DrupalTestCase.
+ *
+ * @param $test_id
+ * Tests with the same id are reported together.
+ */
+ public function __construct($test_id = NULL) {
+ $this->testId = $test_id;
+ }
+
+ /**
+ * Internal helper: stores the assert.
+ *
+ * @param $status
+ * Can be 'pass', 'fail', 'exception'.
+ * TRUE is a synonym for 'pass', FALSE for 'fail'.
+ * @param $message
+ * The message string.
+ * @param $group
+ * Which group this assert belongs to.
+ * @param $caller
+ * By default, the assert comes from a function whose name starts with
+ * 'test'. Instead, you can specify where this assert originates from
+ * by passing in an associative array as $caller. Key 'file' is
+ * the name of the source file, 'line' is the line number and 'function'
+ * is the caller function itself.
+ */
+ protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
+ // Convert boolean status to string status.
+ if (is_bool($status)) {
+ $status = $status ? 'pass' : 'fail';
+ }
+
+ // Increment summary result counter.
+ $this->results['#' . $status]++;
+
+ // Get the function information about the call to the assertion method.
+ if (!$caller) {
+ $caller = $this->getAssertionCall();
+ }
+
+ // Creation assertion array that can be displayed while tests are running.
+ $this->assertions[] = $assertion = array(
+ 'test_id' => $this->testId,
+ 'test_class' => get_class($this),
+ 'status' => $status,
+ 'message' => $message,
+ 'message_group' => $group,
+ 'function' => $caller['function'],
+ 'line' => $caller['line'],
+ 'file' => $caller['file'],
+ );
+
+ // Store assertion for display after the test has completed.
+ try {
+ $connection = Database::getConnection('default', 'simpletest_original_default');
+ }
+ catch (DatabaseConnectionNotDefinedException $e) {
+ // If the test was not set up, the simpletest_original_default
+ // connection does not exist.
+ $connection = Database::getConnection('default', 'default');
+ }
+ $connection
+ ->insert('simpletest')
+ ->fields($assertion)
+ ->execute();
+
+ // We do not use a ternary operator here to allow a breakpoint on
+ // test failure.
+ if ($status == 'pass') {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Store an assertion from outside the testing context.
+ *
+ * This is useful for inserting assertions that can only be recorded after
+ * the test case has been destroyed, such as PHP fatal errors. The caller
+ * information is not automatically gathered since the caller is most likely
+ * inserting the assertion on behalf of other code. In all other respects
+ * the method behaves just like DrupalTestCase::assert() in terms of storing
+ * the assertion.
+ *
+ * @return
+ * Message ID of the stored assertion.
+ *
+ * @see DrupalTestCase::assert()
+ * @see DrupalTestCase::deleteAssert()
+ */
+ public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) {
+ // Convert boolean status to string status.
+ if (is_bool($status)) {
+ $status = $status ? 'pass' : 'fail';
+ }
+
+ $caller += array(
+ 'function' => t('Unknown'),
+ 'line' => 0,
+ 'file' => t('Unknown'),
+ );
+
+ $assertion = array(
+ 'test_id' => $test_id,
+ 'test_class' => $test_class,
+ 'status' => $status,
+ 'message' => $message,
+ 'message_group' => $group,
+ 'function' => $caller['function'],
+ 'line' => $caller['line'],
+ 'file' => $caller['file'],
+ );
+
+ return db_insert('simpletest')
+ ->fields($assertion)
+ ->execute();
+ }
+
+ /**
+ * Delete an assertion record by message ID.
+ *
+ * @param $message_id
+ * Message ID of the assertion to delete.
+ * @return
+ * TRUE if the assertion was deleted, FALSE otherwise.
+ *
+ * @see DrupalTestCase::insertAssert()
+ */
+ public static function deleteAssert($message_id) {
+ return (bool) db_delete('simpletest')
+ ->condition('message_id', $message_id)
+ ->execute();
+ }
+
+ /**
+ * Cycles through backtrace until the first non-assertion method is found.
+ *
+ * @return
+ * Array representing the true caller.
+ */
+ protected function getAssertionCall() {
+ $backtrace = debug_backtrace();
+
+ // The first element is the call. The second element is the caller.
+ // We skip calls that occurred in one of the methods of our base classes
+ // or in an assertion function.
+ while (($caller = $backtrace[1]) &&
+ ((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) ||
+ substr($caller['function'], 0, 6) == 'assert')) {
+ // We remove that call.
+ array_shift($backtrace);
+ }
+
+ return _drupal_get_last_caller($backtrace);
+ }
+
+ /**
+ * Check to see if a value is not false (not an empty string, 0, NULL, or FALSE).
+ *
+ * @param $value
+ * The value on which the assertion is to be done.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertTrue($value, $message = '', $group = 'Other') {
+ return $this->assert((bool) $value, $message ? $message : t('Value @value is TRUE.', array('@value' => var_export($value, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if a value is false (an empty string, 0, NULL, or FALSE).
+ *
+ * @param $value
+ * The value on which the assertion is to be done.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertFalse($value, $message = '', $group = 'Other') {
+ return $this->assert(!$value, $message ? $message : t('Value @value is FALSE.', array('@value' => var_export($value, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if a value is NULL.
+ *
+ * @param $value
+ * The value on which the assertion is to be done.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNull($value, $message = '', $group = 'Other') {
+ return $this->assert(!isset($value), $message ? $message : t('Value @value is NULL.', array('@value' => var_export($value, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if a value is not NULL.
+ *
+ * @param $value
+ * The value on which the assertion is to be done.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNotNull($value, $message = '', $group = 'Other') {
+ return $this->assert(isset($value), $message ? $message : t('Value @value is not NULL.', array('@value' => var_export($value, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if two values are equal.
+ *
+ * @param $first
+ * The first value to check.
+ * @param $second
+ * The second value to check.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertEqual($first, $second, $message = '', $group = 'Other') {
+ return $this->assert($first == $second, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if two values are not equal.
+ *
+ * @param $first
+ * The first value to check.
+ * @param $second
+ * The second value to check.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNotEqual($first, $second, $message = '', $group = 'Other') {
+ return $this->assert($first != $second, $message ? $message : t('Value @first is not equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if two values are identical.
+ *
+ * @param $first
+ * The first value to check.
+ * @param $second
+ * The second value to check.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertIdentical($first, $second, $message = '', $group = 'Other') {
+ return $this->assert($first === $second, $message ? $message : t('Value @first is identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
+ }
+
+ /**
+ * Check to see if two values are not identical.
+ *
+ * @param $first
+ * The first value to check.
+ * @param $second
+ * The second value to check.
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') {
+ return $this->assert($first !== $second, $message ? $message : t('Value @first is not identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
+ }
+
+ /**
+ * Fire an assertion that is always positive.
+ *
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * TRUE.
+ */
+ protected function pass($message = NULL, $group = 'Other') {
+ return $this->assert(TRUE, $message, $group);
+ }
+
+ /**
+ * Fire an assertion that is always negative.
+ *
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @return
+ * FALSE.
+ */
+ protected function fail($message = NULL, $group = 'Other') {
+ return $this->assert(FALSE, $message, $group);
+ }
+
+ /**
+ * Fire an error assertion.
+ *
+ * @param $message
+ * The message to display along with the assertion.
+ * @param $group
+ * The type of assertion - examples are "Browser", "PHP".
+ * @param $caller
+ * The caller of the error.
+ * @return
+ * FALSE.
+ */
+ protected function error($message = '', $group = 'Other', array $caller = NULL) {
+ if ($group == 'User notice') {
+ // Since 'User notice' is set by trigger_error() which is used for debug
+ // set the message to a status of 'debug'.
+ return $this->assert('debug', $message, 'Debug', $caller);
+ }
+
+ return $this->assert('exception', $message, $group, $caller);
+ }
+
+ /**
+ * Logs verbose message in a text file.
+ *
+ * The a link to the vebose message will be placed in the test results via
+ * as a passing assertion with the text '[verbose message]'.
+ *
+ * @param $message
+ * The verbose message to be stored.
+ *
+ * @see simpletest_verbose()
+ */
+ protected function verbose($message) {
+ if ($id = simpletest_verbose($message)) {
+ $class_safe = str_replace('\\', '_', get_class($this));
+ $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . $class_safe . '-' . $id . '.html');
+ $this->error(l(t('Verbose message'), $url, array('attributes' => array('target' => '_blank'))), 'User notice');
+ }
+ }
+
+ /**
+ * Run all tests in this class.
+ *
+ * Regardless of whether $methods are passed or not, only method names
+ * starting with "test" are executed.
+ *
+ * @param $methods
+ * (optional) A list of method names in the test case class to run; e.g.,
+ * array('testFoo', 'testBar'). By default, all methods of the class are
+ * taken into account, but it can be useful to only run a few selected test
+ * methods during debugging.
+ */
+ public function run(array $methods = array()) {
+ // Initialize verbose debugging.
+ $class = get_class($this);
+ simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), str_replace('\\', '_', $class));
+
+ // HTTP auth settings (<username>:<password>) for the simpletest browser
+ // when sending requests to the test site.
+ $this->httpauth_method = variable_get('simpletest_httpauth_method', CURLAUTH_BASIC);
+ $username = variable_get('simpletest_httpauth_username', NULL);
+ $password = variable_get('simpletest_httpauth_password', NULL);
+ if ($username && $password) {
+ $this->httpauth_credentials = $username . ':' . $password;
+ }
+
+ set_error_handler(array($this, 'errorHandler'));
+ // Iterate through all the methods in this class, unless a specific list of
+ // methods to run was passed.
+ $class_methods = get_class_methods($class);
+ if ($methods) {
+ $class_methods = array_intersect($class_methods, $methods);
+ }
+ foreach ($class_methods as $method) {
+ // If the current method starts with "test", run it - it's a test.
+ if (strtolower(substr($method, 0, 4)) == 'test') {
+ // Insert a fail record. This will be deleted on completion to ensure
+ // that testing completed.
+ $method_info = new ReflectionMethod($class, $method);
+ $caller = array(
+ 'file' => $method_info->getFileName(),
+ 'line' => $method_info->getStartLine(),
+ 'function' => $class . '->' . $method . '()',
+ );
+ $completion_check_id = DrupalTestCase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller);
+ $this->setUp();
+ if ($this->setup) {
+ try {
+ $this->$method();
+ // Finish up.
+ }
+ catch (Exception $e) {
+ $this->exceptionHandler($e);
+ }
+ $this->tearDown();
+ }
+ else {
+ $this->fail(t("The test cannot be executed because it has not been set up properly."));
+ }
+ // Remove the completion check record.
+ DrupalTestCase::deleteAssert($completion_check_id);
+ }
+ }
+ // Clear out the error messages and restore error handler.
+ drupal_get_messages();
+ restore_error_handler();
+ }
+
+ /**
+ * Handle errors during test runs.
+ *
+ * Because this is registered in set_error_handler(), it has to be public.
+ * @see set_error_handler
+ */
+ public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
+ if ($severity & error_reporting()) {
+ $error_map = array(
+ E_STRICT => 'Run-time notice',
+ E_WARNING => 'Warning',
+ E_NOTICE => 'Notice',
+ E_CORE_ERROR => 'Core error',
+ E_CORE_WARNING => 'Core warning',
+ E_USER_ERROR => 'User error',
+ E_USER_WARNING => 'User warning',
+ E_USER_NOTICE => 'User notice',
+ E_RECOVERABLE_ERROR => 'Recoverable error',
+ );
+
+ // PHP 5.3 adds new error logging constants. Add these conditionally for
+ // backwards compatibility with PHP 5.2.
+ if (defined('E_DEPRECATED')) {
+ $error_map += array(
+ E_DEPRECATED => 'Deprecated',
+ E_USER_DEPRECATED => 'User deprecated',
+ );
+ }
+
+ $backtrace = debug_backtrace();
+ $this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace));
+ }
+ return TRUE;
+ }
+
+ /**
+ * Handle exceptions.
+ *
+ * @see set_exception_handler
+ */
+ protected function exceptionHandler($exception) {
+ $backtrace = $exception->getTrace();
+ // Push on top of the backtrace the call that generated the exception.
+ array_unshift($backtrace, array(
+ 'line' => $exception->getLine(),
+ 'file' => $exception->getFile(),
+ ));
+ require_once DRUPAL_ROOT . '/includes/errors.inc';
+ // The exception message is run through check_plain() by _drupal_decode_exception().
+ $this->error(t('%type: !message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace));
+ }
+
+ /**
+ * Generates a random string of ASCII characters of codes 32 to 126.
+ *
+ * The generated string includes alpha-numeric characters and common
+ * miscellaneous characters. Use this method when testing general input
+ * where the content is not restricted.
+ *
+ * Do not use this method when special characters are not possible (e.g., in
+ * machine or file names that have already been validated); instead,
+ * use DrupalWebTestCase::randomName().
+ *
+ * @param $length
+ * Length of random string to generate.
+ *
+ * @return
+ * Randomly generated string.
+ *
+ * @see DrupalWebTestCase::randomName()
+ */
+ public static function randomString($length = 8) {
+ $str = '';
+ for ($i = 0; $i < $length; $i++) {
+ $str .= chr(mt_rand(32, 126));
+ }
+ return $str;
+ }
+
+ /**
+ * Generates a random string containing letters and numbers.
+ *
+ * The string will always start with a letter. The letters may be upper or
+ * lower case. This method is better for restricted inputs that do not
+ * accept certain characters. For example, when testing input fields that
+ * require machine readable values (i.e. without spaces and non-standard
+ * characters) this method is best.
+ *
+ * Do not use this method when testing unvalidated user input. Instead, use
+ * DrupalWebTestCase::randomString().
+ *
+ * @param $length
+ * Length of random string to generate.
+ *
+ * @return
+ * Randomly generated string.
+ *
+ * @see DrupalWebTestCase::randomString()
+ */
+ public static function randomName($length = 8) {
+ $values = array_merge(range(65, 90), range(97, 122), range(48, 57));
+ $max = count($values) - 1;
+ $str = chr(mt_rand(97, 122));
+ for ($i = 1; $i < $length; $i++) {
+ $str .= chr($values[mt_rand(0, $max)]);
+ }
+ return $str;
+ }
+
+ /**
+ * Converts a list of possible parameters into a stack of permutations.
+ *
+ * Takes a list of parameters containing possible values, and converts all of
+ * them into a list of items containing every possible permutation.
+ *
+ * Example:
+ * @code
+ * $parameters = array(
+ * 'one' => array(0, 1),
+ * 'two' => array(2, 3),
+ * );
+ * $permutations = DrupalTestCase::generatePermutations($parameters)
+ * // Result:
+ * $permutations == array(
+ * array('one' => 0, 'two' => 2),
+ * array('one' => 1, 'two' => 2),
+ * array('one' => 0, 'two' => 3),
+ * array('one' => 1, 'two' => 3),
+ * )
+ * @endcode
+ *
+ * @param $parameters
+ * An associative array of parameters, keyed by parameter name, and whose
+ * values are arrays of parameter values.
+ *
+ * @return
+ * A list of permutations, which is an array of arrays. Each inner array
+ * contains the full list of parameters that have been passed, but with a
+ * single value only.
+ */
+ public static function generatePermutations($parameters) {
+ $all_permutations = array(array());
+ foreach ($parameters as $parameter => $values) {
+ $new_permutations = array();
+ // Iterate over all values of the parameter.
+ foreach ($values as $value) {
+ // Iterate over all existing permutations.
+ foreach ($all_permutations as $permutation) {
+ // Add the new parameter value to existing permutations.
+ $new_permutations[] = $permutation + array($parameter => $value);
+ }
+ }
+ // Replace the old permutations with the new permutations.
+ $all_permutations = $new_permutations;
+ }
+ return $all_permutations;
+ }
+}
+
+/**
+ * Test case for Drupal unit tests.
+ *
+ * These tests can not access the database nor files. Calling any Drupal
+ * function that needs the database will throw exceptions. These include
+ * watchdog(), module_implements(), module_invoke_all() etc.
+ */
+class DrupalUnitTestCase extends DrupalTestCase {
+
+ /**
+ * Constructor for DrupalUnitTestCase.
+ */
+ function __construct($test_id = NULL) {
+ parent::__construct($test_id);
+ $this->skipClasses[__CLASS__] = TRUE;
+ }
+
+ /**
+ * Sets up unit test environment.
+ *
+ * Unlike DrupalWebTestCase::setUp(), DrupalUnitTestCase::setUp() does not
+ * install modules because tests are performed without accessing the database.
+ * Any required files must be explicitly included by the child class setUp()
+ * method.
+ */
+ protected function setUp() {
+ global $conf;
+
+ // Store necessary current values before switching to the test environment.
+ $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
+
+ // Reset all statics so that test is performed with a clean environment.
+ drupal_static_reset();
+
+ // Generate temporary prefixed database to ensure that tests have a clean starting point.
+ $this->databasePrefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
+
+ // Create test directory.
+ $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
+ file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ $conf['file_public_path'] = $public_files_directory;
+
+ // Clone the current connection and replace the current prefix.
+ $connection_info = Database::getConnectionInfo('default');
+ Database::renameConnection('default', 'simpletest_original_default');
+ foreach ($connection_info as $target => $value) {
+ $connection_info[$target]['prefix'] = array(
+ 'default' => $value['prefix']['default'] . $this->databasePrefix,
+ );
+ }
+ Database::addConnectionInfo('default', 'default', $connection_info['default']);
+
+ // Set user agent to be consistent with web test case.
+ $_SERVER['HTTP_USER_AGENT'] = $this->databasePrefix;
+
+ // If locale is enabled then t() will try to access the database and
+ // subsequently will fail as the database is not accessible.
+ $module_list = module_list();
+ if (isset($module_list['locale'])) {
+ // Transform the list into the format expected as input to module_list().
+ foreach ($module_list as &$module) {
+ $module = array('filename' => drupal_get_filename('module', $module));
+ }
+ $this->originalModuleList = $module_list;
+ unset($module_list['locale']);
+ module_list(TRUE, FALSE, FALSE, $module_list);
+ }
+ $this->setup = TRUE;
+ }
+
+ protected function tearDown() {
+ global $conf;
+
+ // Get back to the original connection.
+ Database::removeConnection('default');
+ Database::renameConnection('simpletest_original_default', 'default');
+
+ $conf['file_public_path'] = $this->originalFileDirectory;
+ // Restore modules if necessary.
+ if (isset($this->originalModuleList)) {
+ module_list(TRUE, FALSE, FALSE, $this->originalModuleList);
+ }
+ }
+}
+
+/**
+ * Test case for typical Drupal tests.
+ */
+class DrupalWebTestCase extends DrupalTestCase {
+ /**
+ * The profile to install as a basis for testing.
+ *
+ * @var string
+ */
+ protected $profile = 'standard';
+
+ /**
+ * The URL currently loaded in the internal browser.
+ *
+ * @var string
+ */
+ protected $url;
+
+ /**
+ * The handle of the current cURL connection.
+ *
+ * @var resource
+ */
+ protected $curlHandle;
+
+ /**
+ * The headers of the page currently loaded in the internal browser.
+ *
+ * @var Array
+ */
+ protected $headers;
+
+ /**
+ * The content of the page currently loaded in the internal browser.
+ *
+ * @var string
+ */
+ protected $content;
+
+ /**
+ * The content of the page currently loaded in the internal browser (plain text version).
+ *
+ * @var string
+ */
+ protected $plainTextContent;
+
+ /**
+ * The value of the Drupal.settings JavaScript variable for the page currently loaded in the internal browser.
+ *
+ * @var Array
+ */
+ protected $drupalSettings;
+
+ /**
+ * The parsed version of the page.
+ *
+ * @var SimpleXMLElement
+ */
+ protected $elements = NULL;
+
+ /**
+ * The current user logged in using the internal browser.
+ *
+ * @var bool
+ */
+ protected $loggedInUser = FALSE;
+
+ /**
+ * The current cookie file used by cURL.
+ *
+ * We do not reuse the cookies in further runs, so we do not need a file
+ * but we still need cookie handling, so we set the jar to NULL.
+ */
+ protected $cookieFile = NULL;
+
+ /**
+ * Additional cURL options.
+ *
+ * DrupalWebTestCase itself never sets this but always obeys what is set.
+ */
+ protected $additionalCurlOptions = array();
+
+ /**
+ * The original user, before it was changed to a clean uid = 1 for testing purposes.
+ *
+ * @var object
+ */
+ protected $originalUser = NULL;
+
+ /**
+ * The original shutdown handlers array, before it was cleaned for testing purposes.
+ *
+ * @var array
+ */
+ protected $originalShutdownCallbacks = array();
+
+ /**
+ * HTTP authentication method
+ */
+ protected $httpauth_method = CURLAUTH_BASIC;
+
+ /**
+ * HTTP authentication credentials (<username>:<password>).
+ */
+ protected $httpauth_credentials = NULL;
+
+ /**
+ * The current session name, if available.
+ */
+ protected $session_name = NULL;
+
+ /**
+ * The current session ID, if available.
+ */
+ protected $session_id = NULL;
+
+ /**
+ * Whether the files were copied to the test files directory.
+ */
+ protected $generatedTestFiles = FALSE;
+
+ /**
+ * The number of redirects followed during the handling of a request.
+ */
+ protected $redirect_count;
+
+ /**
+ * Constructor for DrupalWebTestCase.
+ */
+ function __construct($test_id = NULL) {
+ parent::__construct($test_id);
+ $this->skipClasses[__CLASS__] = TRUE;
+ }
+
+ /**
+ * Get a node from the database based on its title.
+ *
+ * @param $title
+ * A node title, usually generated by $this->randomName().
+ * @param $reset
+ * (optional) Whether to reset the internal node_load() cache.
+ *
+ * @return
+ * A node object matching $title.
+ */
+ function drupalGetNodeByTitle($title, $reset = FALSE) {
+ $nodes = node_load_multiple(array(), array('title' => $title), $reset);
+ // Load the first node returned from the database.
+ $returned_node = reset($nodes);
+ return $returned_node;
+ }
+
+ /**
+ * Creates a node based on default settings.
+ *
+ * @param $settings
+ * An associative array of settings to change from the defaults, keys are
+ * node properties, for example 'title' => 'Hello, world!'.
+ * @return
+ * Created node object.
+ */
+ protected function drupalCreateNode($settings = array()) {
+ // Populate defaults array.
+ $settings += array(
+ 'body' => array(LANGUAGE_NONE => array(array())),
+ 'title' => $this->randomName(8),
+ 'comment' => 2,
+ 'changed' => REQUEST_TIME,
+ 'moderate' => 0,
+ 'promote' => 0,
+ 'revision' => 1,
+ 'log' => '',
+ 'status' => 1,
+ 'sticky' => 0,
+ 'type' => 'page',
+ 'revisions' => NULL,
+ 'language' => LANGUAGE_NONE,
+ );
+
+ // Use the original node's created time for existing nodes.
+ if (isset($settings['created']) && !isset($settings['date'])) {
+ $settings['date'] = format_date($settings['created'], 'custom', 'Y-m-d H:i:s O');
+ }
+
+ // If the node's user uid is not specified manually, use the currently
+ // logged in user if available, or else the user running the test.
+ if (!isset($settings['uid'])) {
+ if ($this->loggedInUser) {
+ $settings['uid'] = $this->loggedInUser->uid;
+ }
+ else {
+ global $user;
+ $settings['uid'] = $user->uid;
+ }
+ }
+
+ // Merge body field value and format separately.
+ $body = array(
+ 'value' => $this->randomName(32),
+ 'format' => filter_default_format(),
+ );
+ $settings['body'][$settings['language']][0] += $body;
+
+ $node = (object) $settings;
+ node_save($node);
+
+ // Small hack to link revisions to our test user.
+ db_update('node_revision')
+ ->fields(array('uid' => $node->uid))
+ ->condition('vid', $node->vid)
+ ->execute();
+ return $node;
+ }
+
+ /**
+ * Creates a custom content type based on default settings.
+ *
+ * @param $settings
+ * An array of settings to change from the defaults.
+ * Example: 'type' => 'foo'.
+ * @return
+ * Created content type.
+ */
+ protected function drupalCreateContentType($settings = array()) {
+ // Find a non-existent random type name.
+ do {
+ $name = strtolower($this->randomName(8));
+ } while (node_type_get_type($name));
+
+ // Populate defaults array.
+ $defaults = array(
+ 'type' => $name,
+ 'name' => $name,
+ 'base' => 'node_content',
+ 'description' => '',
+ 'help' => '',
+ 'title_label' => 'Title',
+ 'body_label' => 'Body',
+ 'has_title' => 1,
+ 'has_body' => 1,
+ );
+ // Imposed values for a custom type.
+ $forced = array(
+ 'orig_type' => '',
+ 'old_type' => '',
+ 'module' => 'node',
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ );
+ $type = $forced + $settings + $defaults;
+ $type = (object) $type;
+
+ $saved_type = node_type_save($type);
+ node_types_rebuild();
+ menu_rebuild();
+ node_add_body_field($type);
+
+ $this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
+
+ // Reset permissions so that permissions for this content type are available.
+ $this->checkPermissions(array(), TRUE);
+
+ return $type;
+ }
+
+ /**
+ * Get a list files that can be used in tests.
+ *
+ * @param $type
+ * File type, possible values: 'binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'.
+ * @param $size
+ * File size in bytes to match. Please check the tests/files folder.
+ * @return
+ * List of files that match filter.
+ */
+ protected function drupalGetTestFiles($type, $size = NULL) {
+ if (empty($this->generatedTestFiles)) {
+ // Generate binary test files.
+ $lines = array(64, 1024);
+ $count = 0;
+ foreach ($lines as $line) {
+ simpletest_generate_file('binary-' . $count++, 64, $line, 'binary');
+ }
+
+ // Generate text test files.
+ $lines = array(16, 256, 1024, 2048, 20480);
+ $count = 0;
+ foreach ($lines as $line) {
+ simpletest_generate_file('text-' . $count++, 64, $line);
+ }
+
+ // Copy other test files from simpletest.
+ $original = drupal_get_path('module', 'simpletest') . '/files';
+ $files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/');
+ foreach ($files as $file) {
+ file_unmanaged_copy($file->uri, variable_get('file_public_path', conf_path() . '/files'));
+ }
+
+ $this->generatedTestFiles = TRUE;
+ }
+
+ $files = array();
+ // Make sure type is valid.
+ if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
+ $files = file_scan_directory('public://', '/' . $type . '\-.*/');
+
+ // If size is set then remove any files that are not of that size.
+ if ($size !== NULL) {
+ foreach ($files as $file) {
+ $stats = stat($file->uri);
+ if ($stats['size'] != $size) {
+ unset($files[$file->uri]);
+ }
+ }
+ }
+ }
+ usort($files, array($this, 'drupalCompareFiles'));
+ return $files;
+ }
+
+ /**
+ * Compare two files based on size and file name.
+ */
+ protected function drupalCompareFiles($file1, $file2) {
+ $compare_size = filesize($file1->uri) - filesize($file2->uri);
+ if ($compare_size) {
+ // Sort by file size.
+ return $compare_size;
+ }
+ else {
+ // The files were the same size, so sort alphabetically.
+ return strnatcmp($file1->name, $file2->name);
+ }
+ }
+
+ /**
+ * Create a user with a given set of permissions.
+ *
+ * @param array $permissions
+ * Array of permission names to assign to user. Note that the user always
+ * has the default permissions derived from the "authenticated users" role.
+ *
+ * @return object|false
+ * A fully loaded user object with pass_raw property, or FALSE if account
+ * creation fails.
+ */
+ protected function drupalCreateUser(array $permissions = array()) {
+ // Create a role with the given permission set, if any.
+ $rid = FALSE;
+ if ($permissions) {
+ $rid = $this->drupalCreateRole($permissions);
+ if (!$rid) {
+ return FALSE;
+ }
+ }
+
+ // Create a user assigned to that role.
+ $edit = array();
+ $edit['name'] = $this->randomName();
+ $edit['mail'] = $edit['name'] . '@example.com';
+ $edit['pass'] = user_password();
+ $edit['status'] = 1;
+ if ($rid) {
+ $edit['roles'] = array($rid => $rid);
+ }
+
+ $account = user_save(drupal_anonymous_user(), $edit);
+
+ $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login'));
+ if (empty($account->uid)) {
+ return FALSE;
+ }
+
+ // Add the raw password so that we can log in as this user.
+ $account->pass_raw = $edit['pass'];
+ return $account;
+ }
+
+ /**
+ * Internal helper function; Create a role with specified permissions.
+ *
+ * @param $permissions
+ * Array of permission names to assign to role.
+ * @param $name
+ * (optional) String for the name of the role. Defaults to a random string.
+ * @return
+ * Role ID of newly created role, or FALSE if role creation failed.
+ */
+ protected function drupalCreateRole(array $permissions, $name = NULL) {
+ // Generate random name if it was not passed.
+ if (!$name) {
+ $name = $this->randomName();
+ }
+
+ // Check the all the permissions strings are valid.
+ if (!$this->checkPermissions($permissions)) {
+ return FALSE;
+ }
+
+ // Create new role.
+ $role = new stdClass();
+ $role->name = $name;
+ user_role_save($role);
+ user_role_grant_permissions($role->rid, $permissions);
+
+ $this->assertTrue(isset($role->rid), t('Created role of name: @name, id: @rid', array('@name' => $name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role'));
+ if ($role && !empty($role->rid)) {
+ $count = db_query('SELECT COUNT(*) FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchField();
+ $this->assertTrue($count == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
+ return $role->rid;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Check to make sure that the array of permissions are valid.
+ *
+ * @param $permissions
+ * Permissions to check.
+ * @param $reset
+ * Reset cached available permissions.
+ * @return
+ * TRUE or FALSE depending on whether the permissions are valid.
+ */
+ protected function checkPermissions(array $permissions, $reset = FALSE) {
+ $available = &drupal_static(__FUNCTION__);
+
+ if (!isset($available) || $reset) {
+ $available = array_keys(module_invoke_all('permission'));
+ }
+
+ $valid = TRUE;
+ foreach ($permissions as $permission) {
+ if (!in_array($permission, $available)) {
+ $this->fail(t('Invalid permission %permission.', array('%permission' => $permission)), t('Role'));
+ $valid = FALSE;
+ }
+ }
+ return $valid;
+ }
+
+ /**
+ * Log in a user with the internal browser.
+ *
+ * If a user is already logged in, then the current user is logged out before
+ * logging in the specified user.
+ *
+ * Please note that neither the global $user nor the passed-in user object is
+ * populated with data of the logged in user. If you need full access to the
+ * user object after logging in, it must be updated manually. If you also need
+ * access to the plain-text password of the user (set by drupalCreateUser()),
+ * e.g. to log in the same user again, then it must be re-assigned manually.
+ * For example:
+ * @code
+ * // Create a user.
+ * $account = $this->drupalCreateUser(array());
+ * $this->drupalLogin($account);
+ * // Load real user object.
+ * $pass_raw = $account->pass_raw;
+ * $account = user_load($account->uid);
+ * $account->pass_raw = $pass_raw;
+ * @endcode
+ *
+ * @param $account
+ * User object representing the user to log in.
+ *
+ * @see drupalCreateUser()
+ */
+ protected function drupalLogin(stdClass $account) {
+ if ($this->loggedInUser) {
+ $this->drupalLogout();
+ }
+
+ $edit = array(
+ 'name' => $account->name,
+ 'pass' => $account->pass_raw
+ );
+ $this->drupalPost('user', $edit, t('Log in'));
+
+ // If a "log out" link appears on the page, it is almost certainly because
+ // the login was successful.
+ $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $account->name)), t('User login'));
+
+ if ($pass) {
+ $this->loggedInUser = $account;
+ }
+ }
+
+ /**
+ * Generate a token for the currently logged in user.
+ */
+ protected function drupalGetToken($value = '') {
+ $private_key = drupal_get_private_key();
+ return drupal_hmac_base64($value, $this->session_id . $private_key);
+ }
+
+ /*
+ * Logs a user out of the internal browser, then check the login page to confirm logout.
+ */
+ protected function drupalLogout() {
+ // Make a request to the logout page, and redirect to the user page, the
+ // idea being if you were properly logged out you should be seeing a login
+ // screen.
+ $this->drupalGet('user/logout');
+ $this->drupalGet('user');
+ $pass = $this->assertField('name', t('Username field found.'), t('Logout'));
+ $pass = $pass && $this->assertField('pass', t('Password field found.'), t('Logout'));
+
+ if ($pass) {
+ $this->loggedInUser = FALSE;
+ }
+ }
+
+ /**
+ * Generates a database prefix for running tests.
+ *
+ * The generated database table prefix is used for the Drupal installation
+ * being performed for the test. It is also used as user agent HTTP header
+ * value by the cURL-based browser of DrupalWebTestCase, which is sent
+ * to the Drupal installation of the test. During early Drupal bootstrap, the
+ * user agent HTTP header is parsed, and if it matches, all database queries
+ * use the database table prefix that has been generated here.
+ *
+ * @see DrupalWebTestCase::curlInitialize()
+ * @see drupal_valid_test_ua()
+ * @see DrupalWebTestCase::setUp()
+ */
+ protected function prepareDatabasePrefix() {
+ $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
+
+ // As soon as the database prefix is set, the test might start to execute.
+ // All assertions as well as the SimpleTest batch operations are associated
+ // with the testId, so the database prefix has to be associated with it.
+ db_update('simpletest_test_id')
+ ->fields(array('last_prefix' => $this->databasePrefix))
+ ->condition('test_id', $this->testId)
+ ->execute();
+ }
+
+ /**
+ * Changes the database connection to the prefixed one.
+ *
+ * @see DrupalWebTestCase::setUp()
+ */
+ protected function changeDatabasePrefix() {
+ if (empty($this->databasePrefix)) {
+ $this->prepareDatabasePrefix();
+ // If $this->prepareDatabasePrefix() failed to work, return without
+ // setting $this->setupDatabasePrefix to TRUE, so setUp() methods will
+ // know to bail out.
+ if (empty($this->databasePrefix)) {
+ return;
+ }
+ }
+
+ // Clone the current connection and replace the current prefix.
+ $connection_info = Database::getConnectionInfo('default');
+ Database::renameConnection('default', 'simpletest_original_default');
+ foreach ($connection_info as $target => $value) {
+ $connection_info[$target]['prefix'] = array(
+ 'default' => $value['prefix']['default'] . $this->databasePrefix,
+ );
+ }
+ Database::addConnectionInfo('default', 'default', $connection_info['default']);
+
+ // Indicate the database prefix was set up correctly.
+ $this->setupDatabasePrefix = TRUE;
+ }
+
+ /**
+ * Prepares the current environment for running the test.
+ *
+ * Backups various current environment variables and resets them, so they do
+ * not interfere with the Drupal site installation in which tests are executed
+ * and can be restored in tearDown().
+ *
+ * Also sets up new resources for the testing environment, such as the public
+ * filesystem and configuration directories.
+ *
+ * @see DrupalWebTestCase::setUp()
+ * @see DrupalWebTestCase::tearDown()
+ */
+ protected function prepareEnvironment() {
+ global $user, $language, $conf;
+
+ // Store necessary current values before switching to prefixed database.
+ $this->originalLanguage = $language;
+ $this->originalLanguageDefault = variable_get('language_default');
+ $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
+ $this->originalProfile = drupal_get_profile();
+ $this->originalCleanUrl = variable_get('clean_url', 0);
+ $this->originalUser = $user;
+
+ // Set to English to prevent exceptions from utf8_truncate() from t()
+ // during install if the current language is not 'en'.
+ // The following array/object conversion is copied from language_default().
+ $language = (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => '');
+
+ // Save and clean the shutdown callbacks array because it is static cached
+ // and will be changed by the test run. Otherwise it will contain callbacks
+ // from both environments and the testing environment will try to call the
+ // handlers defined by the original one.
+ $callbacks = &drupal_register_shutdown_function();
+ $this->originalShutdownCallbacks = $callbacks;
+ $callbacks = array();
+
+ // Create test directory ahead of installation so fatal errors and debug
+ // information can be logged during installation process.
+ // Use temporary files directory with the same prefix as the database.
+ $this->public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
+ $this->private_files_directory = $this->public_files_directory . '/private';
+ $this->temp_files_directory = $this->private_files_directory . '/temp';
+
+ // Create the directories
+ file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
+ file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
+ $this->generatedTestFiles = FALSE;
+
+ // Log fatal errors.
+ ini_set('log_errors', 1);
+ ini_set('error_log', $this->public_files_directory . '/error.log');
+
+ // Set the test information for use in other parts of Drupal.
+ $test_info = &$GLOBALS['drupal_test_info'];
+ $test_info['test_run_id'] = $this->databasePrefix;
+ $test_info['in_child_site'] = FALSE;
+
+ // Indicate the environment was set up correctly.
+ $this->setupEnvironment = TRUE;
+ }
+
+ /**
+ * Sets up a Drupal site for running functional and integration tests.
+ *
+ * Generates a random database prefix and installs Drupal with the specified
+ * installation profile in DrupalWebTestCase::$profile into the
+ * prefixed database. Afterwards, installs any additional modules specified by
+ * the test.
+ *
+ * After installation all caches are flushed and several configuration values
+ * are reset to the values of the parent site executing the test, since the
+ * default values may be incompatible with the environment in which tests are
+ * being executed.
+ *
+ * @param ...
+ * List of modules to enable for the duration of the test. This can be
+ * either a single array or a variable number of string arguments.
+ *
+ * @see DrupalWebTestCase::prepareDatabasePrefix()
+ * @see DrupalWebTestCase::changeDatabasePrefix()
+ * @see DrupalWebTestCase::prepareEnvironment()
+ */
+ protected function setUp() {
+ global $user, $language, $conf;
+
+ // Create the database prefix for this test.
+ $this->prepareDatabasePrefix();
+
+ // Prepare the environment for running tests.
+ $this->prepareEnvironment();
+ if (!$this->setupEnvironment) {
+ return FALSE;
+ }
+
+ // Reset all statics and variables to perform tests in a clean environment.
+ $conf = array();
+ drupal_static_reset();
+
+ // Change the database prefix.
+ // All static variables need to be reset before the database prefix is
+ // changed, since DrupalCacheArray implementations attempt to
+ // write back to persistent caches when they are destructed.
+ $this->changeDatabasePrefix();
+ if (!$this->setupDatabasePrefix) {
+ return FALSE;
+ }
+
+ // Preset the 'install_profile' system variable, so the first call into
+ // system_rebuild_module_data() (in drupal_install_system()) will register
+ // the test's profile as a module. Without this, the installation profile of
+ // the parent site (executing the test) is registered, and the test
+ // profile's hook_install() and other hook implementations are never invoked.
+ $conf['install_profile'] = $this->profile;
+
+ // Perform the actual Drupal installation.
+ include_once DRUPAL_ROOT . '/includes/install.inc';
+ drupal_install_system();
+
+ $this->preloadRegistry();
+
+ // Set path variables.
+ variable_set('file_public_path', $this->public_files_directory);
+ variable_set('file_private_path', $this->private_files_directory);
+ variable_set('file_temporary_path', $this->temp_files_directory);
+
+ // Set the 'simpletest_parent_profile' variable to add the parent profile's
+ // search path to the child site's search paths.
+ // @see drupal_system_listing()
+ // @todo This may need to be primed like 'install_profile' above.
+ variable_set('simpletest_parent_profile', $this->originalProfile);
+
+ // Include the testing profile.
+ variable_set('install_profile', $this->profile);
+ $profile_details = install_profile_info($this->profile, 'en');
+
+ // Install the modules specified by the testing profile.
+ module_enable($profile_details['dependencies'], FALSE);
+
+ // Install modules needed for this test. This could have been passed in as
+ // either a single array argument or a variable number of string arguments.
+ // @todo Remove this compatibility layer in Drupal 8, and only accept
+ // $modules as a single array argument.
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ if ($modules) {
+ $success = module_enable($modules, TRUE);
+ $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
+ }
+
+ // Run the profile tasks.
+ $install_profile_module_exists = db_query("SELECT 1 FROM {system} WHERE type = 'module' AND name = :name", array(
+ ':name' => $this->profile,
+ ))->fetchField();
+ if ($install_profile_module_exists) {
+ module_enable(array($this->profile), FALSE);
+ }
+
+ // Reset/rebuild all data structures after enabling the modules.
+ $this->resetAll();
+
+ // Run cron once in that environment, as install.php does at the end of
+ // the installation process.
+ drupal_cron_run();
+
+ // Ensure that the session is not written to the new environment and replace
+ // the global $user session with uid 1 from the new test site.
+ drupal_save_session(FALSE);
+ // Login as uid 1.
+ $user = user_load(1);
+
+ // Restore necessary variables.
+ variable_set('install_task', 'done');
+ variable_set('clean_url', $this->originalCleanUrl);
+ variable_set('site_mail', 'simpletest@example.com');
+ variable_set('date_default_timezone', date_default_timezone_get());
+
+ // Set up English language.
+ unset($conf['language_default']);
+ $language = language_default();
+
+ // Use the test mail class instead of the default mail handler class.
+ variable_set('mail_system', array('default-system' => 'TestingMailSystem'));
+
+ drupal_set_time_limit($this->timeLimit);
+ $this->setup = TRUE;
+ }
+
+ /**
+ * Preload the registry from the testing site.
+ *
+ * This method is called by DrupalWebTestCase::setUp(), and preloads the
+ * registry from the testing site to cut down on the time it takes to
+ * set up a clean environment for the current test run.
+ */
+ protected function preloadRegistry() {
+ // Use two separate queries, each with their own connections: copy the
+ // {registry} and {registry_file} tables over from the parent installation
+ // to the child installation.
+ $original_connection = Database::getConnection('default', 'simpletest_original_default');
+ $test_connection = Database::getConnection();
+
+ foreach (array('registry', 'registry_file') as $table) {
+ // Find the records from the parent database.
+ $source_query = $original_connection
+ ->select($table, array(), array('fetch' => PDO::FETCH_ASSOC))
+ ->fields($table);
+
+ $dest_query = $test_connection->insert($table);
+
+ $first = TRUE;
+ foreach ($source_query->execute() as $row) {
+ if ($first) {
+ $dest_query->fields(array_keys($row));
+ $first = FALSE;
+ }
+ // Insert the records into the child database.
+ $dest_query->values($row);
+ }
+
+ $dest_query->execute();
+ }
+ }
+
+ /**
+ * Reset all data structures after having enabled new modules.
+ *
+ * This method is called by DrupalWebTestCase::setUp() after enabling
+ * the requested modules. It must be called again when additional modules
+ * are enabled later.
+ */
+ protected function resetAll() {
+ // Reset all static variables.
+ drupal_static_reset();
+ // Reset the list of enabled modules.
+ module_list(TRUE);
+
+ // Reset cached schema for new database prefix. This must be done before
+ // drupal_flush_all_caches() so rebuilds can make use of the schema of
+ // modules enabled on the cURL side.
+ drupal_get_schema(NULL, TRUE);
+
+ // Perform rebuilds and flush remaining caches.
+ drupal_flush_all_caches();
+
+ // Reload global $conf array and permissions.
+ $this->refreshVariables();
+ $this->checkPermissions(array(), TRUE);
+ }
+
+ /**
+ * Refresh the in-memory set of variables. Useful after a page request is made
+ * that changes a variable in a different thread.
+ *
+ * In other words calling a settings page with $this->drupalPost() with a changed
+ * value would update a variable to reflect that change, but in the thread that
+ * made the call (thread running the test) the changed variable would not be
+ * picked up.
+ *
+ * This method clears the variables cache and loads a fresh copy from the database
+ * to ensure that the most up-to-date set of variables is loaded.
+ */
+ protected function refreshVariables() {
+ global $conf;
+ cache_clear_all('variables', 'cache_bootstrap');
+ $conf = variable_initialize();
+ }
+
+ /**
+ * Delete created files and temporary files directory, delete the tables created by setUp(),
+ * and reset the database prefix.
+ */
+ protected function tearDown() {
+ global $user, $language;
+
+ // In case a fatal error occurred that was not in the test process read the
+ // log to pick up any fatal errors.
+ simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE);
+
+ $emailCount = count(variable_get('drupal_test_email_collector', array()));
+ if ($emailCount) {
+ $message = format_plural($emailCount, '1 e-mail was sent during this test.', '@count e-mails were sent during this test.');
+ $this->pass($message, t('E-mail'));
+ }
+
+ // Delete temporary files directory.
+ file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10));
+
+ // Remove all prefixed tables.
+ $tables = db_find_tables($this->databasePrefix . '%');
+ $connection_info = Database::getConnectionInfo('default');
+ $tables = db_find_tables($connection_info['default']['prefix']['default'] . '%');
+ if (empty($tables)) {
+ $this->fail('Failed to find test tables to drop.');
+ }
+ $prefix_length = strlen($connection_info['default']['prefix']['default']);
+ foreach ($tables as $table) {
+ if (db_drop_table(substr($table, $prefix_length))) {
+ unset($tables[$table]);
+ }
+ }
+ if (!empty($tables)) {
+ $this->fail('Failed to drop all prefixed tables.');
+ }
+
+ // Get back to the original connection.
+ Database::removeConnection('default');
+ Database::renameConnection('simpletest_original_default', 'default');
+
+ // Restore original shutdown callbacks array to prevent original
+ // environment of calling handlers from test run.
+ $callbacks = &drupal_register_shutdown_function();
+ $callbacks = $this->originalShutdownCallbacks;
+
+ // Return the user to the original one.
+ $user = $this->originalUser;
+ drupal_save_session(TRUE);
+
+ // Ensure that internal logged in variable and cURL options are reset.
+ $this->loggedInUser = FALSE;
+ $this->additionalCurlOptions = array();
+
+ // Reload module list and implementations to ensure that test module hooks
+ // aren't called after tests.
+ module_list(TRUE);
+ module_implements('', FALSE, TRUE);
+
+ // Reset the Field API.
+ field_cache_clear();
+
+ // Rebuild caches.
+ $this->refreshVariables();
+
+ // Reset public files directory.
+ $GLOBALS['conf']['file_public_path'] = $this->originalFileDirectory;
+
+ // Reset language.
+ $language = $this->originalLanguage;
+ if ($this->originalLanguageDefault) {
+ $GLOBALS['conf']['language_default'] = $this->originalLanguageDefault;
+ }
+
+ // Close the CURL handler.
+ $this->curlClose();
+ }
+
+ /**
+ * Initializes the cURL connection.
+ *
+ * If the simpletest_httpauth_credentials variable is set, this function will
+ * add HTTP authentication headers. This is necessary for testing sites that
+ * are protected by login credentials from public access.
+ * See the description of $curl_options for other options.
+ */
+ protected function curlInitialize() {
+ global $base_url;
+
+ if (!isset($this->curlHandle)) {
+ $this->curlHandle = curl_init();
+
+ // Some versions/configurations of cURL break on a NULL cookie jar, so
+ // supply a real file.
+ if (empty($this->cookieFile)) {
+ $this->cookieFile = $this->public_files_directory . '/cookie.jar';
+ }
+
+ $curl_options = array(
+ CURLOPT_COOKIEJAR => $this->cookieFile,
+ CURLOPT_URL => $base_url,
+ CURLOPT_FOLLOWLOCATION => FALSE,
+ CURLOPT_RETURNTRANSFER => TRUE,
+ CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on HTTPS.
+ CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on HTTPS.
+ CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'),
+ CURLOPT_USERAGENT => $this->databasePrefix,
+ );
+ if (isset($this->httpauth_credentials)) {
+ $curl_options[CURLOPT_HTTPAUTH] = $this->httpauth_method;
+ $curl_options[CURLOPT_USERPWD] = $this->httpauth_credentials;
+ }
+ // curl_setopt_array() returns FALSE if any of the specified options
+ // cannot be set, and stops processing any further options.
+ $result = curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
+ if (!$result) {
+ throw new Exception('One or more cURL options could not be set.');
+ }
+
+ // By default, the child session name should be the same as the parent.
+ $this->session_name = session_name();
+ }
+ // We set the user agent header on each request so as to use the current
+ // time and a new uniqid.
+ if (preg_match('/simpletest\d+/', $this->databasePrefix, $matches)) {
+ curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0]));
+ }
+ }
+
+ /**
+ * Initializes and executes a cURL request.
+ *
+ * @param $curl_options
+ * An associative array of cURL options to set, where the keys are constants
+ * defined by the cURL library. For a list of valid options, see
+ * http://www.php.net/manual/function.curl-setopt.php
+ * @param $redirect
+ * FALSE if this is an initial request, TRUE if this request is the result
+ * of a redirect.
+ *
+ * @return
+ * The content returned from the call to curl_exec().
+ *
+ * @see curlInitialize()
+ */
+ protected function curlExec($curl_options, $redirect = FALSE) {
+ $this->curlInitialize();
+
+ // cURL incorrectly handles URLs with a fragment by including the
+ // fragment in the request to the server, causing some web servers
+ // to reject the request citing "400 - Bad Request". To prevent
+ // this, we strip the fragment from the request.
+ // TODO: Remove this for Drupal 8, since fixed in curl 7.20.0.
+ if (!empty($curl_options[CURLOPT_URL]) && strpos($curl_options[CURLOPT_URL], '#')) {
+ $original_url = $curl_options[CURLOPT_URL];
+ $curl_options[CURLOPT_URL] = strtok($curl_options[CURLOPT_URL], '#');
+ }
+
+ $url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
+
+ if (!empty($curl_options[CURLOPT_POST])) {
+ // This is a fix for the Curl library to prevent Expect: 100-continue
+ // headers in POST requests, that may cause unexpected HTTP response
+ // codes from some webservers (like lighttpd that returns a 417 error
+ // code). It is done by setting an empty "Expect" header field that is
+ // not overwritten by Curl.
+ $curl_options[CURLOPT_HTTPHEADER][] = 'Expect:';
+ }
+ curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
+
+ if (!$redirect) {
+ // Reset headers, the session ID and the redirect counter.
+ $this->session_id = NULL;
+ $this->headers = array();
+ $this->redirect_count = 0;
+ }
+
+ $content = curl_exec($this->curlHandle);
+ $status = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+
+ // cURL incorrectly handles URLs with fragments, so instead of
+ // letting cURL handle redirects we take of them ourselves to
+ // to prevent fragments being sent to the web server as part
+ // of the request.
+ // TODO: Remove this for Drupal 8, since fixed in curl 7.20.0.
+ if (in_array($status, array(300, 301, 302, 303, 305, 307)) && $this->redirect_count < variable_get('simpletest_maximum_redirects', 5)) {
+ if ($this->drupalGetHeader('location')) {
+ $this->redirect_count++;
+ $curl_options = array();
+ $curl_options[CURLOPT_URL] = $this->drupalGetHeader('location');
+ $curl_options[CURLOPT_HTTPGET] = TRUE;
+ return $this->curlExec($curl_options, TRUE);
+ }
+ }
+
+ $this->drupalSetContent($content, isset($original_url) ? $original_url : curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
+ $message_vars = array(
+ '!method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'),
+ '@url' => isset($original_url) ? $original_url : $url,
+ '@status' => $status,
+ '!length' => format_size(strlen($this->drupalGetContent()))
+ );
+ $message = t('!method @url returned @status (!length).', $message_vars);
+ $this->assertTrue($this->drupalGetContent() !== FALSE, $message, t('Browser'));
+ return $this->drupalGetContent();
+ }
+
+ /**
+ * Reads headers and registers errors received from the tested site.
+ *
+ * @see _drupal_log_error().
+ *
+ * @param $curlHandler
+ * The cURL handler.
+ * @param $header
+ * An header.
+ */
+ protected function curlHeaderCallback($curlHandler, $header) {
+ // Header fields can be extended over multiple lines by preceding each
+ // extra line with at least one SP or HT. They should be joined on receive.
+ // Details are in RFC2616 section 4.
+ if ($header[0] == ' ' || $header[0] == "\t") {
+ // Normalize whitespace between chucks.
+ $this->headers[] = array_pop($this->headers) . ' ' . trim($header);
+ }
+ else {
+ $this->headers[] = $header;
+ }
+
+ // Errors are being sent via X-Drupal-Assertion-* headers,
+ // generated by _drupal_log_error() in the exact form required
+ // by DrupalWebTestCase::error().
+ if (preg_match('/^X-Drupal-Assertion-[0-9]+: (.*)$/', $header, $matches)) {
+ // Call DrupalWebTestCase::error() with the parameters from the header.
+ call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1])));
+ }
+
+ // Save cookies.
+ if (preg_match('/^Set-Cookie: ([^=]+)=(.+)/', $header, $matches)) {
+ $name = $matches[1];
+ $parts = array_map('trim', explode(';', $matches[2]));
+ $value = array_shift($parts);
+ $this->cookies[$name] = array('value' => $value, 'secure' => in_array('secure', $parts));
+ if ($name == $this->session_name) {
+ if ($value != 'deleted') {
+ $this->session_id = $value;
+ }
+ else {
+ $this->session_id = NULL;
+ }
+ }
+ }
+
+ // This is required by cURL.
+ return strlen($header);
+ }
+
+ /**
+ * Close the cURL handler and unset the handler.
+ */
+ protected function curlClose() {
+ if (isset($this->curlHandle)) {
+ curl_close($this->curlHandle);
+ unset($this->curlHandle);
+ }
+ }
+
+ /**
+ * Parse content returned from curlExec using DOM and SimpleXML.
+ *
+ * @return
+ * A SimpleXMLElement or FALSE on failure.
+ */
+ protected function parse() {
+ if (!$this->elements) {
+ // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
+ // them.
+ $htmlDom = new DOMDocument();
+ @$htmlDom->loadHTML($this->drupalGetContent());
+ if ($htmlDom) {
+ $this->pass(t('Valid HTML found on "@path"', array('@path' => $this->getUrl())), t('Browser'));
+ // It's much easier to work with simplexml than DOM, luckily enough
+ // we can just simply import our DOM tree.
+ $this->elements = simplexml_import_dom($htmlDom);
+ }
+ }
+ if (!$this->elements) {
+ $this->fail(t('Parsed page successfully.'), t('Browser'));
+ }
+
+ return $this->elements;
+ }
+
+ /**
+ * Retrieves a Drupal path or an absolute path.
+ *
+ * @param $path
+ * Drupal path or URL to load into internal browser
+ * @param $options
+ * Options to be forwarded to url().
+ * @param $headers
+ * An array containing additional HTTP request headers, each formatted as
+ * "name: value".
+ * @return
+ * The retrieved HTML string, also available as $this->drupalGetContent()
+ */
+ protected function drupalGet($path, array $options = array(), array $headers = array()) {
+ $options['absolute'] = TRUE;
+
+ // We re-using a CURL connection here. If that connection still has certain
+ // options set, it might change the GET into a POST. Make sure we clear out
+ // previous options.
+ $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
+ $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
+
+ // Replace original page output with new output from redirected page(s).
+ if ($new = $this->checkForMetaRefresh()) {
+ $out = $new;
+ }
+ $this->verbose('GET request to: ' . $path .
+ '<hr />Ending URL: ' . $this->getUrl() .
+ '<hr />' . $out);
+ return $out;
+ }
+
+ /**
+ * Retrieve a Drupal path or an absolute path and JSON decode the result.
+ */
+ protected function drupalGetAJAX($path, array $options = array(), array $headers = array()) {
+ return drupal_json_decode($this->drupalGet($path, $options, $headers));
+ }
+
+ /**
+ * Execute a POST request on a Drupal page.
+ * It will be done as usual POST request with SimpleBrowser.
+ *
+ * @param $path
+ * Location of the post form. Either a Drupal path or an absolute path or
+ * NULL to post to the current page. For multi-stage forms you can set the
+ * path to NULL and have it post to the last received page. Example:
+ *
+ * @code
+ * // First step in form.
+ * $edit = array(...);
+ * $this->drupalPost('some_url', $edit, t('Save'));
+ *
+ * // Second step in form.
+ * $edit = array(...);
+ * $this->drupalPost(NULL, $edit, t('Save'));
+ * @endcode
+ * @param $edit
+ * Field data in an associative array. Changes the current input fields
+ * (where possible) to the values indicated. A checkbox can be set to
+ * TRUE to be checked and FALSE to be unchecked. Note that when a form
+ * contains file upload fields, other fields cannot start with the '@'
+ * character.
+ *
+ * Multiple select fields can be set using name[] and setting each of the
+ * possible values. Example:
+ * @code
+ * $edit = array();
+ * $edit['name[]'] = array('value1', 'value2');
+ * @endcode
+ * @param $submit
+ * Value of the submit button whose click is to be emulated. For example,
+ * t('Save'). The processing of the request depends on this value. For
+ * example, a form may have one button with the value t('Save') and another
+ * button with the value t('Delete'), and execute different code depending
+ * on which one is clicked.
+ *
+ * This function can also be called to emulate an Ajax submission. In this
+ * case, this value needs to be an array with the following keys:
+ * - path: A path to submit the form values to for Ajax-specific processing,
+ * which is likely different than the $path parameter used for retrieving
+ * the initial form. Defaults to 'system/ajax'.
+ * - triggering_element: If the value for the 'path' key is 'system/ajax' or
+ * another generic Ajax processing path, this needs to be set to the name
+ * of the element. If the name doesn't identify the element uniquely, then
+ * this should instead be an array with a single key/value pair,
+ * corresponding to the element name and value. The callback for the
+ * generic Ajax processing path uses this to find the #ajax information
+ * for the element, including which specific callback to use for
+ * processing the request.
+ *
+ * This can also be set to NULL in order to emulate an Internet Explorer
+ * submission of a form with a single text field, and pressing ENTER in that
+ * textfield: under these conditions, no button information is added to the
+ * POST data.
+ * @param $options
+ * Options to be forwarded to url().
+ * @param $headers
+ * An array containing additional HTTP request headers, each formatted as
+ * "name: value".
+ * @param $form_html_id
+ * (optional) HTML ID of the form to be submitted. On some pages
+ * there are many identical forms, so just using the value of the submit
+ * button is not enough. For example: 'trigger-node-presave-assign-form'.
+ * Note that this is not the Drupal $form_id, but rather the HTML ID of the
+ * form, which is typically the same thing but with hyphens replacing the
+ * underscores.
+ * @param $extra_post
+ * (optional) A string of additional data to append to the POST submission.
+ * This can be used to add POST data for which there are no HTML fields, as
+ * is done by drupalPostAJAX(). This string is literally appended to the
+ * POST data, so it must already be urlencoded and contain a leading "&"
+ * (e.g., "&extra_var1=hello+world&extra_var2=you%26me").
+ */
+ protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL, $extra_post = NULL) {
+ $submit_matches = FALSE;
+ $ajax = is_array($submit);
+ if (isset($path)) {
+ $this->drupalGet($path, $options);
+ }
+ if ($this->parse()) {
+ $edit_save = $edit;
+ // Let's iterate over all the forms.
+ $xpath = "//form";
+ if (!empty($form_html_id)) {
+ $xpath .= "[@id='" . $form_html_id . "']";
+ }
+ $forms = $this->xpath($xpath);
+ foreach ($forms as $form) {
+ // We try to set the fields of this form as specified in $edit.
+ $edit = $edit_save;
+ $post = array();
+ $upload = array();
+ $submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
+ $action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl();
+ if ($ajax) {
+ $action = $this->getAbsoluteUrl(!empty($submit['path']) ? $submit['path'] : 'system/ajax');
+ // Ajax callbacks verify the triggering element if necessary, so while
+ // we may eventually want extra code that verifies it in the
+ // handleForm() function, it's not currently a requirement.
+ $submit_matches = TRUE;
+ }
+
+ // We post only if we managed to handle every field in edit and the
+ // submit button matches.
+ if (!$edit && ($submit_matches || !isset($submit))) {
+ $post_array = $post;
+ if ($upload) {
+ // TODO: cURL handles file uploads for us, but the implementation
+ // is broken. This is a less than elegant workaround. Alternatives
+ // are being explored at #253506.
+ foreach ($upload as $key => $file) {
+ $file = drupal_realpath($file);
+ if ($file && is_file($file)) {
+ // Use the new CurlFile class for file uploads when using PHP
+ // 5.5 or higher.
+ if (class_exists('CurlFile')) {
+ $post[$key] = curl_file_create($file);
+ }
+ else {
+ $post[$key] = '@' . $file;
+ }
+ }
+ }
+ }
+ else {
+ foreach ($post as $key => $value) {
+ // Encode according to application/x-www-form-urlencoded
+ // Both names and values needs to be urlencoded, according to
+ // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
+ $post[$key] = urlencode($key) . '=' . urlencode($value);
+ }
+ $post = implode('&', $post) . $extra_post;
+ }
+ $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $headers));
+ // Ensure that any changes to variables in the other thread are picked up.
+ $this->refreshVariables();
+
+ // Replace original page output with new output from redirected page(s).
+ if ($new = $this->checkForMetaRefresh()) {
+ $out = $new;
+ }
+ $this->verbose('POST request to: ' . $path .
+ '<hr />Ending URL: ' . $this->getUrl() .
+ '<hr />Fields: ' . highlight_string('<?php ' . var_export($post_array, TRUE), TRUE) .
+ '<hr />' . $out);
+ return $out;
+ }
+ }
+ // We have not found a form which contained all fields of $edit.
+ foreach ($edit as $name => $value) {
+ $this->fail(t('Failed to set field @name to @value', array('@name' => $name, '@value' => $value)));
+ }
+ if (!$ajax && isset($submit)) {
+ $this->assertTrue($submit_matches, t('Found the @submit button', array('@submit' => $submit)));
+ }
+ $this->fail(t('Found the requested form fields at @path', array('@path' => $path)));
+ }
+ }
+
+ /**
+ * Execute an Ajax submission.
+ *
+ * This executes a POST as ajax.js does. It uses the returned JSON data, an
+ * array of commands, to update $this->content using equivalent DOM
+ * manipulation as is used by ajax.js. It also returns the array of commands.
+ *
+ * @param $path
+ * Location of the form containing the Ajax enabled element to test. Can be
+ * either a Drupal path or an absolute path or NULL to use the current page.
+ * @param $edit
+ * Field data in an associative array. Changes the current input fields
+ * (where possible) to the values indicated.
+ * @param $triggering_element
+ * The name of the form element that is responsible for triggering the Ajax
+ * functionality to test. May be a string or, if the triggering element is
+ * a button, an associative array where the key is the name of the button
+ * and the value is the button label. i.e.) array('op' => t('Refresh')).
+ * @param $ajax_path
+ * (optional) Override the path set by the Ajax settings of the triggering
+ * element. In the absence of both the triggering element's Ajax path and
+ * $ajax_path 'system/ajax' will be used.
+ * @param $options
+ * (optional) Options to be forwarded to url().
+ * @param $headers
+ * (optional) An array containing additional HTTP request headers, each
+ * formatted as "name: value". Forwarded to drupalPost().
+ * @param $form_html_id
+ * (optional) HTML ID of the form to be submitted, use when there is more
+ * than one identical form on the same page and the value of the triggering
+ * element is not enough to identify the form. Note this is not the Drupal
+ * ID of the form but rather the HTML ID of the form.
+ * @param $ajax_settings
+ * (optional) An array of Ajax settings which if specified will be used in
+ * place of the Ajax settings of the triggering element.
+ *
+ * @return
+ * An array of Ajax commands.
+ *
+ * @see drupalPost()
+ * @see ajax.js
+ */
+ protected function drupalPostAJAX($path, $edit, $triggering_element, $ajax_path = NULL, array $options = array(), array $headers = array(), $form_html_id = NULL, $ajax_settings = NULL) {
+ // Get the content of the initial page prior to calling drupalPost(), since
+ // drupalPost() replaces $this->content.
+ if (isset($path)) {
+ $this->drupalGet($path, $options);
+ }
+ $content = $this->content;
+ $drupal_settings = $this->drupalSettings;
+
+ // Get the Ajax settings bound to the triggering element.
+ if (!isset($ajax_settings)) {
+ if (is_array($triggering_element)) {
+ $xpath = '//*[@name="' . key($triggering_element) . '" and @value="' . current($triggering_element) . '"]';
+ }
+ else {
+ $xpath = '//*[@name="' . $triggering_element . '"]';
+ }
+ if (isset($form_html_id)) {
+ $xpath = '//form[@id="' . $form_html_id . '"]' . $xpath;
+ }
+ $element = $this->xpath($xpath);
+ $element_id = (string) $element[0]['id'];
+ $ajax_settings = $drupal_settings['ajax'][$element_id];
+ }
+
+ // Add extra information to the POST data as ajax.js does.
+ $extra_post = '';
+ if (isset($ajax_settings['submit'])) {
+ foreach ($ajax_settings['submit'] as $key => $value) {
+ $extra_post .= '&' . urlencode($key) . '=' . urlencode($value);
+ }
+ }
+ foreach ($this->xpath('//*[@id]') as $element) {
+ $id = (string) $element['id'];
+ $extra_post .= '&' . urlencode('ajax_html_ids[]') . '=' . urlencode($id);
+ }
+ if (isset($drupal_settings['ajaxPageState'])) {
+ $extra_post .= '&' . urlencode('ajax_page_state[theme]') . '=' . urlencode($drupal_settings['ajaxPageState']['theme']);
+ $extra_post .= '&' . urlencode('ajax_page_state[theme_token]') . '=' . urlencode($drupal_settings['ajaxPageState']['theme_token']);
+ foreach ($drupal_settings['ajaxPageState']['css'] as $key => $value) {
+ $extra_post .= '&' . urlencode("ajax_page_state[css][$key]") . '=1';
+ }
+ foreach ($drupal_settings['ajaxPageState']['js'] as $key => $value) {
+ $extra_post .= '&' . urlencode("ajax_page_state[js][$key]") . '=1';
+ }
+ }
+
+ // Unless a particular path is specified, use the one specified by the
+ // Ajax settings, or else 'system/ajax'.
+ if (!isset($ajax_path)) {
+ $ajax_path = isset($ajax_settings['url']) ? $ajax_settings['url'] : 'system/ajax';
+ }
+
+ // Submit the POST request.
+ $return = drupal_json_decode($this->drupalPost(NULL, $edit, array('path' => $ajax_path, 'triggering_element' => $triggering_element), $options, $headers, $form_html_id, $extra_post));
+
+ // Change the page content by applying the returned commands.
+ if (!empty($ajax_settings) && !empty($return)) {
+ // ajax.js applies some defaults to the settings object, so do the same
+ // for what's used by this function.
+ $ajax_settings += array(
+ 'method' => 'replaceWith',
+ );
+ // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
+ // them.
+ $dom = new DOMDocument();
+ @$dom->loadHTML($content);
+ // XPath allows for finding wrapper nodes better than DOM does.
+ $xpath = new DOMXPath($dom);
+ foreach ($return as $command) {
+ switch ($command['command']) {
+ case 'settings':
+ $drupal_settings = drupal_array_merge_deep($drupal_settings, $command['settings']);
+ break;
+
+ case 'insert':
+ $wrapperNode = NULL;
+ // When a command doesn't specify a selector, use the
+ // #ajax['wrapper'] which is always an HTML ID.
+ if (!isset($command['selector'])) {
+ $wrapperNode = $xpath->query('//*[@id="' . $ajax_settings['wrapper'] . '"]')->item(0);
+ }
+ // @todo Ajax commands can target any jQuery selector, but these are
+ // hard to fully emulate with XPath. For now, just handle 'head'
+ // and 'body', since these are used by ajax_render().
+ elseif (in_array($command['selector'], array('head', 'body'))) {
+ $wrapperNode = $xpath->query('//' . $command['selector'])->item(0);
+ }
+ if ($wrapperNode) {
+ // ajax.js adds an enclosing DIV to work around a Safari bug.
+ $newDom = new DOMDocument();
+ $newDom->loadHTML('<div>' . $command['data'] . '</div>');
+ $newNode = $dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE);
+ $method = isset($command['method']) ? $command['method'] : $ajax_settings['method'];
+ // The "method" is a jQuery DOM manipulation function. Emulate
+ // each one using PHP's DOMNode API.
+ switch ($method) {
+ case 'replaceWith':
+ $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
+ break;
+ case 'append':
+ $wrapperNode->appendChild($newNode);
+ break;
+ case 'prepend':
+ // If no firstChild, insertBefore() falls back to
+ // appendChild().
+ $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
+ break;
+ case 'before':
+ $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
+ break;
+ case 'after':
+ // If no nextSibling, insertBefore() falls back to
+ // appendChild().
+ $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
+ break;
+ case 'html':
+ foreach ($wrapperNode->childNodes as $childNode) {
+ $wrapperNode->removeChild($childNode);
+ }
+ $wrapperNode->appendChild($newNode);
+ break;
+ }
+ }
+ break;
+
+ // @todo Add suitable implementations for these commands in order to
+ // have full test coverage of what ajax.js can do.
+ case 'remove':
+ break;
+ case 'changed':
+ break;
+ case 'css':
+ break;
+ case 'data':
+ break;
+ case 'restripe':
+ break;
+ }
+ }
+ $content = $dom->saveHTML();
+ }
+ $this->drupalSetContent($content);
+ $this->drupalSetSettings($drupal_settings);
+ return $return;
+ }
+
+ /**
+ * Runs cron in the Drupal installed by Simpletest.
+ */
+ protected function cronRun() {
+ $this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))));
+ }
+
+ /**
+ * Check for meta refresh tag and if found call drupalGet() recursively. This
+ * function looks for the http-equiv attribute to be set to "Refresh"
+ * and is case-sensitive.
+ *
+ * @return
+ * Either the new page content or FALSE.
+ */
+ protected function checkForMetaRefresh() {
+ if (strpos($this->drupalGetContent(), '<meta ') && $this->parse()) {
+ $refresh = $this->xpath('//meta[@http-equiv="Refresh"]');
+ if (!empty($refresh)) {
+ // Parse the content attribute of the meta tag for the format:
+ // "[delay]: URL=[page_to_redirect_to]".
+ if (preg_match('/\d+;\s*URL=(?P<url>.*)/i', $refresh[0]['content'], $match)) {
+ return $this->drupalGet($this->getAbsoluteUrl(decode_entities($match['url'])));
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Retrieves only the headers for a Drupal path or an absolute path.
+ *
+ * @param $path
+ * Drupal path or URL to load into internal browser
+ * @param $options
+ * Options to be forwarded to url().
+ * @param $headers
+ * An array containing additional HTTP request headers, each formatted as
+ * "name: value".
+ * @return
+ * The retrieved headers, also available as $this->drupalGetContent()
+ */
+ protected function drupalHead($path, array $options = array(), array $headers = array()) {
+ $options['absolute'] = TRUE;
+ $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HTTPHEADER => $headers));
+ $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
+ return $out;
+ }
+
+ /**
+ * Handle form input related to drupalPost(). Ensure that the specified fields
+ * exist and attempt to create POST data in the correct manner for the particular
+ * field type.
+ *
+ * @param $post
+ * Reference to array of post values.
+ * @param $edit
+ * Reference to array of edit values to be checked against the form.
+ * @param $submit
+ * Form submit button value.
+ * @param $form
+ * Array of form elements.
+ * @return
+ * Submit value matches a valid submit input in the form.
+ */
+ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
+ // Retrieve the form elements.
+ $elements = $form->xpath('.//input[not(@disabled)]|.//textarea[not(@disabled)]|.//select[not(@disabled)]');
+ $submit_matches = FALSE;
+ foreach ($elements as $element) {
+ // SimpleXML objects need string casting all the time.
+ $name = (string) $element['name'];
+ // This can either be the type of <input> or the name of the tag itself
+ // for <select> or <textarea>.
+ $type = isset($element['type']) ? (string) $element['type'] : $element->getName();
+ $value = isset($element['value']) ? (string) $element['value'] : '';
+ $done = FALSE;
+ if (isset($edit[$name])) {
+ switch ($type) {
+ case 'text':
+ case 'tel':
+ case 'textarea':
+ case 'url':
+ case 'number':
+ case 'range':
+ case 'color':
+ case 'hidden':
+ case 'password':
+ case 'email':
+ case 'search':
+ $post[$name] = $edit[$name];
+ unset($edit[$name]);
+ break;
+ case 'radio':
+ if ($edit[$name] == $value) {
+ $post[$name] = $edit[$name];
+ unset($edit[$name]);
+ }
+ break;
+ case 'checkbox':
+ // To prevent checkbox from being checked.pass in a FALSE,
+ // otherwise the checkbox will be set to its value regardless
+ // of $edit.
+ if ($edit[$name] === FALSE) {
+ unset($edit[$name]);
+ continue 2;
+ }
+ else {
+ unset($edit[$name]);
+ $post[$name] = $value;
+ }
+ break;
+ case 'select':
+ $new_value = $edit[$name];
+ $options = $this->getAllOptions($element);
+ if (is_array($new_value)) {
+ // Multiple select box.
+ if (!empty($new_value)) {
+ $index = 0;
+ $key = preg_replace('/\[\]$/', '', $name);
+ foreach ($options as $option) {
+ $option_value = (string) $option['value'];
+ if (in_array($option_value, $new_value)) {
+ $post[$key . '[' . $index++ . ']'] = $option_value;
+ $done = TRUE;
+ unset($edit[$name]);
+ }
+ }
+ }
+ else {
+ // No options selected: do not include any POST data for the
+ // element.
+ $done = TRUE;
+ unset($edit[$name]);
+ }
+ }
+ else {
+ // Single select box.
+ foreach ($options as $option) {
+ if ($new_value == $option['value']) {
+ $post[$name] = $new_value;
+ unset($edit[$name]);
+ $done = TRUE;
+ break;
+ }
+ }
+ }
+ break;
+ case 'file':
+ $upload[$name] = $edit[$name];
+ unset($edit[$name]);
+ break;
+ }
+ }
+ if (!isset($post[$name]) && !$done) {
+ switch ($type) {
+ case 'textarea':
+ $post[$name] = (string) $element;
+ break;
+ case 'select':
+ $single = empty($element['multiple']);
+ $first = TRUE;
+ $index = 0;
+ $key = preg_replace('/\[\]$/', '', $name);
+ $options = $this->getAllOptions($element);
+ foreach ($options as $option) {
+ // For single select, we load the first option, if there is a
+ // selected option that will overwrite it later.
+ if ($option['selected'] || ($first && $single)) {
+ $first = FALSE;
+ if ($single) {
+ $post[$name] = (string) $option['value'];
+ }
+ else {
+ $post[$key . '[' . $index++ . ']'] = (string) $option['value'];
+ }
+ }
+ }
+ break;
+ case 'file':
+ break;
+ case 'submit':
+ case 'image':
+ if (isset($submit) && $submit == $value) {
+ $post[$name] = $value;
+ $submit_matches = TRUE;
+ }
+ break;
+ case 'radio':
+ case 'checkbox':
+ if (!isset($element['checked'])) {
+ break;
+ }
+ // Deliberate no break.
+ default:
+ $post[$name] = $value;
+ }
+ }
+ }
+ return $submit_matches;
+ }
+
+ /**
+ * Builds an XPath query.
+ *
+ * Builds an XPath query by replacing placeholders in the query by the value
+ * of the arguments.
+ *
+ * XPath 1.0 (the version supported by libxml2, the underlying XML library
+ * used by PHP) doesn't support any form of quotation. This function
+ * simplifies the building of XPath expression.
+ *
+ * @param $xpath
+ * An XPath query, possibly with placeholders in the form ':name'.
+ * @param $args
+ * An array of arguments with keys in the form ':name' matching the
+ * placeholders in the query. The values may be either strings or numeric
+ * values.
+ * @return
+ * An XPath query with arguments replaced.
+ */
+ protected function buildXPathQuery($xpath, array $args = array()) {
+ // Replace placeholders.
+ foreach ($args as $placeholder => $value) {
+ // XPath 1.0 doesn't support a way to escape single or double quotes in a
+ // string literal. We split double quotes out of the string, and encode
+ // them separately.
+ if (is_string($value)) {
+ // Explode the text at the quote characters.
+ $parts = explode('"', $value);
+
+ // Quote the parts.
+ foreach ($parts as &$part) {
+ $part = '"' . $part . '"';
+ }
+
+ // Return the string.
+ $value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0];
+ }
+ $xpath = preg_replace('/' . preg_quote($placeholder) . '\b/', $value, $xpath);
+ }
+ return $xpath;
+ }
+
+ /**
+ * Perform an xpath search on the contents of the internal browser. The search
+ * is relative to the root element (HTML tag normally) of the page.
+ *
+ * @param $xpath
+ * The xpath string to use in the search.
+ * @return
+ * The return value of the xpath search. For details on the xpath string
+ * format and return values see the SimpleXML documentation,
+ * http://us.php.net/manual/function.simplexml-element-xpath.php.
+ */
+ protected function xpath($xpath, array $arguments = array()) {
+ if ($this->parse()) {
+ $xpath = $this->buildXPathQuery($xpath, $arguments);
+ $result = $this->elements->xpath($xpath);
+ // Some combinations of PHP / libxml versions return an empty array
+ // instead of the documented FALSE. Forcefully convert any falsish values
+ // to an empty array to allow foreach(...) constructions.
+ return $result ? $result : array();
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Get all option elements, including nested options, in a select.
+ *
+ * @param $element
+ * The element for which to get the options.
+ * @return
+ * Option elements in select.
+ */
+ protected function getAllOptions(SimpleXMLElement $element) {
+ $options = array();
+ // Add all options items.
+ foreach ($element->option as $option) {
+ $options[] = $option;
+ }
+
+ // Search option group children.
+ if (isset($element->optgroup)) {
+ foreach ($element->optgroup as $group) {
+ $options = array_merge($options, $this->getAllOptions($group));
+ }
+ }
+ return $options;
+ }
+
+ /**
+ * Pass if a link with the specified label is found, and optional with the
+ * specified index.
+ *
+ * @param $label
+ * Text between the anchor tags.
+ * @param $index
+ * Link position counting from zero.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertLink($label, $index = 0, $message = '', $group = 'Other') {
+ $links = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => $label));
+ $message = ($message ? $message : t('Link with label %label found.', array('%label' => $label)));
+ return $this->assert(isset($links[$index]), $message, $group);
+ }
+
+ /**
+ * Pass if a link with the specified label is not found.
+ *
+ * @param $label
+ * Text between the anchor tags.
+ * @param $index
+ * Link position counting from zero.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNoLink($label, $message = '', $group = 'Other') {
+ $links = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => $label));
+ $message = ($message ? $message : t('Link with label %label not found.', array('%label' => $label)));
+ return $this->assert(empty($links), $message, $group);
+ }
+
+ /**
+ * Pass if a link containing a given href (part) is found.
+ *
+ * @param $href
+ * The full or partial value of the 'href' attribute of the anchor tag.
+ * @param $index
+ * Link position counting from zero.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ *
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertLinkByHref($href, $index = 0, $message = '', $group = 'Other') {
+ $links = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href));
+ $message = ($message ? $message : t('Link containing href %href found.', array('%href' => $href)));
+ return $this->assert(isset($links[$index]), $message, $group);
+ }
+
+ /**
+ * Pass if a link containing a given href (part) is not found.
+ *
+ * @param $href
+ * The full or partial value of the 'href' attribute of the anchor tag.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ *
+ * @return
+ * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ protected function assertNoLinkByHref($href, $message = '', $group = 'Other') {
+ $links = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href));
+ $message = ($message ? $message : t('No link containing href %href found.', array('%href' => $href)));
+ return $this->assert(empty($links), $message, $group);
+ }
+
+ /**
+ * Follows a link by name.
+ *
+ * Will click the first link found with this link text by default, or a later
+ * one if an index is given. Match is case sensitive with normalized space.
+ * The label is translated label. There is an assert for successful click.
+ *
+ * @param $label
+ * Text between the anchor tags.
+ * @param $index
+ * Link position counting from zero.
+ * @return
+ * Page on success, or FALSE on failure.
+ */
+ protected function clickLink($label, $index = 0) {
+ $url_before = $this->getUrl();
+ $urls = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => $label));
+
+ if (isset($urls[$index])) {
+ $url_target = $this->getAbsoluteUrl($urls[$index]['href']);
+ }
+
+ $this->assertTrue(isset($urls[$index]), t('Clicked link %label (@url_target) from @url_before', array('%label' => $label, '@url_target' => $url_target, '@url_before' => $url_before)), t('Browser'));
+
+ if (isset($url_target)) {
+ return $this->drupalGet($url_target);
+ }
+ return FALSE;
+ }
+
+ /**
+ * Takes a path and returns an absolute path.
+ *
+ * @param $path
+ * A path from the internal browser content.
+ * @return
+ * The $path with $base_url prepended, if necessary.
+ */
+ protected function getAbsoluteUrl($path) {
+ global $base_url, $base_path;
+
+ $parts = parse_url($path);
+ if (empty($parts['host'])) {
+ // Ensure that we have a string (and no xpath object).
+ $path = (string) $path;
+ // Strip $base_path, if existent.
+ $length = strlen($base_path);
+ if (substr($path, 0, $length) === $base_path) {
+ $path = substr($path, $length);
+ }
+ // Ensure that we have an absolute path.
+ if ($path[0] !== '/') {
+ $path = '/' . $path;
+ }
+ // Finally, prepend the $base_url.
+ $path = $base_url . $path;
+ }
+ return $path;
+ }
+
+ /**
+ * Get the current URL from the cURL handler.
+ *
+ * @return
+ * The current URL.
+ */
+ protected function getUrl() {
+ return $this->url;
+ }
+
+ /**
+ * Gets the HTTP response headers of the requested page. Normally we are only
+ * interested in the headers returned by the last request. However, if a page
+ * is redirected or HTTP authentication is in use, multiple requests will be
+ * required to retrieve the page. Headers from all requests may be requested
+ * by passing TRUE to this function.
+ *
+ * @param $all_requests
+ * Boolean value specifying whether to return headers from all requests
+ * instead of just the last request. Defaults to FALSE.
+ * @return
+ * A name/value array if headers from only the last request are requested.
+ * If headers from all requests are requested, an array of name/value
+ * arrays, one for each request.
+ *
+ * The pseudonym ":status" is used for the HTTP status line.
+ *
+ * Values for duplicate headers are stored as a single comma-separated list.
+ */
+ protected function drupalGetHeaders($all_requests = FALSE) {
+ $request = 0;
+ $headers = array($request => array());
+ foreach ($this->headers as $header) {
+ $header = trim($header);
+ if ($header === '') {
+ $request++;
+ }
+ else {
+ if (strpos($header, 'HTTP/') === 0) {
+ $name = ':status';
+ $value = $header;
+ }
+ else {
+ list($name, $value) = explode(':', $header, 2);
+ $name = strtolower($name);
+ }
+ if (isset($headers[$request][$name])) {
+ $headers[$request][$name] .= ',' . trim($value);
+ }
+ else {
+ $headers[$request][$name] = trim($value);
+ }
+ }
+ }
+ if (!$all_requests) {
+ $headers = array_pop($headers);
+ }
+ return $headers;
+ }
+
+ /**
+ * Gets the value of an HTTP response header. If multiple requests were
+ * required to retrieve the page, only the headers from the last request will
+ * be checked by default. However, if TRUE is passed as the second argument,
+ * all requests will be processed from last to first until the header is
+ * found.
+ *
+ * @param $name
+ * The name of the header to retrieve. Names are case-insensitive (see RFC
+ * 2616 section 4.2).
+ * @param $all_requests
+ * Boolean value specifying whether to check all requests if the header is
+ * not found in the last request. Defaults to FALSE.
+ * @return
+ * The HTTP header value or FALSE if not found.
+ */
+ protected function drupalGetHeader($name, $all_requests = FALSE) {
+ $name = strtolower($name);
+ $header = FALSE;
+ if ($all_requests) {
+ foreach (array_reverse($this->drupalGetHeaders(TRUE)) as $headers) {
+ if (isset($headers[$name])) {
+ $header = $headers[$name];
+ break;
+ }
+ }
+ }
+ else {
+ $headers = $this->drupalGetHeaders();
+ if (isset($headers[$name])) {
+ $header = $headers[$name];
+ }
+ }
+ return $header;
+ }
+
+ /**
+ * Gets the current raw HTML of requested page.
+ */
+ protected function drupalGetContent() {
+ return $this->content;
+ }
+
+ /**
+ * Gets the value of the Drupal.settings JavaScript variable for the currently loaded page.
+ */
+ protected function drupalGetSettings() {
+ return $this->drupalSettings;
+ }
+
+ /**
+ * Gets an array containing all e-mails sent during this test case.
+ *
+ * @param $filter
+ * An array containing key/value pairs used to filter the e-mails that are returned.
+ * @return
+ * An array containing e-mail messages captured during the current test.
+ */
+ protected function drupalGetMails($filter = array()) {
+ $captured_emails = variable_get('drupal_test_email_collector', array());
+ $filtered_emails = array();
+
+ foreach ($captured_emails as $message) {
+ foreach ($filter as $key => $value) {
+ if (!isset($message[$key]) || $message[$key] != $value) {
+ continue 2;
+ }
+ }
+ $filtered_emails[] = $message;
+ }
+
+ return $filtered_emails;
+ }
+
+ /**
+ * Sets the raw HTML content. This can be useful when a page has been fetched
+ * outside of the internal browser and assertions need to be made on the
+ * returned page.
+ *
+ * A good example would be when testing drupal_http_request(). After fetching
+ * the page the content can be set and page elements can be checked to ensure
+ * that the function worked properly.
+ */
+ protected function drupalSetContent($content, $url = 'internal:') {
+ $this->content = $content;
+ $this->url = $url;
+ $this->plainTextContent = FALSE;
+ $this->elements = FALSE;
+ $this->drupalSettings = array();
+ if (preg_match('/jQuery\.extend\(Drupal\.settings, (.*?)\);/', $content, $matches)) {
+ $this->drupalSettings = drupal_json_decode($matches[1]);
+ }
+ }
+
+ /**
+ * Sets the value of the Drupal.settings JavaScript variable for the currently loaded page.
+ */
+ protected function drupalSetSettings($settings) {
+ $this->drupalSettings = $settings;
+ }
+
+ /**
+ * Pass if the internal browser's URL matches the given path.
+ *
+ * @param $path
+ * The expected system path.
+ * @param $options
+ * (optional) Any additional options to pass for $path to url().
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertUrl($path, array $options = array(), $message = '', $group = 'Other') {
+ if (!$message) {
+ $message = t('Current URL is @url.', array(
+ '@url' => var_export(url($path, $options), TRUE),
+ ));
+ }
+ $options['absolute'] = TRUE;
+ return $this->assertEqual($this->getUrl(), url($path, $options), $message, $group);
+ }
+
+ /**
+ * Pass if the raw text IS found on the loaded page, fail otherwise. Raw text
+ * refers to the raw HTML that the page generated.
+ *
+ * @param $raw
+ * Raw (HTML) string to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertRaw($raw, $message = '', $group = 'Other') {
+ if (!$message) {
+ $message = t('Raw "@raw" found', array('@raw' => $raw));
+ }
+ return $this->assert(strpos($this->drupalGetContent(), $raw) !== FALSE, $message, $group);
+ }
+
+ /**
+ * Pass if the raw text is NOT found on the loaded page, fail otherwise. Raw text
+ * refers to the raw HTML that the page generated.
+ *
+ * @param $raw
+ * Raw (HTML) string to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoRaw($raw, $message = '', $group = 'Other') {
+ if (!$message) {
+ $message = t('Raw "@raw" not found', array('@raw' => $raw));
+ }
+ return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
+ }
+
+ /**
+ * Pass if the text IS found on the text version of the page. The text version
+ * is the equivalent of what a user would see when viewing through a web browser.
+ * In other words the HTML has been filtered out of the contents.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertText($text, $message = '', $group = 'Other') {
+ return $this->assertTextHelper($text, $message, $group, FALSE);
+ }
+
+ /**
+ * Pass if the text is NOT found on the text version of the page. The text version
+ * is the equivalent of what a user would see when viewing through a web browser.
+ * In other words the HTML has been filtered out of the contents.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoText($text, $message = '', $group = 'Other') {
+ return $this->assertTextHelper($text, $message, $group, TRUE);
+ }
+
+ /**
+ * Helper for assertText and assertNoText.
+ *
+ * It is not recommended to call this function directly.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @param $not_exists
+ * TRUE if this text should not exist, FALSE if it should.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertTextHelper($text, $message = '', $group, $not_exists) {
+ if ($this->plainTextContent === FALSE) {
+ $this->plainTextContent = filter_xss($this->drupalGetContent(), array());
+ }
+ if (!$message) {
+ $message = !$not_exists ? t('"@text" found', array('@text' => $text)) : t('"@text" not found', array('@text' => $text));
+ }
+ return $this->assert($not_exists == (strpos($this->plainTextContent, $text) === FALSE), $message, $group);
+ }
+
+ /**
+ * Pass if the text is found ONLY ONCE on the text version of the page.
+ *
+ * The text version is the equivalent of what a user would see when viewing
+ * through a web browser. In other words the HTML has been filtered out of
+ * the contents.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertUniqueText($text, $message = '', $group = 'Other') {
+ return $this->assertUniqueTextHelper($text, $message, $group, TRUE);
+ }
+
+ /**
+ * Pass if the text is found MORE THAN ONCE on the text version of the page.
+ *
+ * The text version is the equivalent of what a user would see when viewing
+ * through a web browser. In other words the HTML has been filtered out of
+ * the contents.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to, defaults to 'Other'.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoUniqueText($text, $message = '', $group = 'Other') {
+ return $this->assertUniqueTextHelper($text, $message, $group, FALSE);
+ }
+
+ /**
+ * Helper for assertUniqueText and assertNoUniqueText.
+ *
+ * It is not recommended to call this function directly.
+ *
+ * @param $text
+ * Plain text to look for.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @param $be_unique
+ * TRUE if this text should be found only once, FALSE if it should be found more than once.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertUniqueTextHelper($text, $message = '', $group, $be_unique) {
+ if ($this->plainTextContent === FALSE) {
+ $this->plainTextContent = filter_xss($this->drupalGetContent(), array());
+ }
+ if (!$message) {
+ $message = '"' . $text . '"' . ($be_unique ? ' found only once' : ' found more than once');
+ }
+ $first_occurance = strpos($this->plainTextContent, $text);
+ if ($first_occurance === FALSE) {
+ return $this->assert(FALSE, $message, $group);
+ }
+ $offset = $first_occurance + strlen($text);
+ $second_occurance = strpos($this->plainTextContent, $text, $offset);
+ return $this->assert($be_unique == ($second_occurance === FALSE), $message, $group);
+ }
+
+ /**
+ * Will trigger a pass if the Perl regex pattern is found in the raw content.
+ *
+ * @param $pattern
+ * Perl regex to look for including the regex delimiters.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertPattern($pattern, $message = '', $group = 'Other') {
+ if (!$message) {
+ $message = t('Pattern "@pattern" found', array('@pattern' => $pattern));
+ }
+ return $this->assert((bool) preg_match($pattern, $this->drupalGetContent()), $message, $group);
+ }
+
+ /**
+ * Will trigger a pass if the perl regex pattern is not present in raw content.
+ *
+ * @param $pattern
+ * Perl regex to look for including the regex delimiters.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoPattern($pattern, $message = '', $group = 'Other') {
+ if (!$message) {
+ $message = t('Pattern "@pattern" not found', array('@pattern' => $pattern));
+ }
+ return $this->assert(!preg_match($pattern, $this->drupalGetContent()), $message, $group);
+ }
+
+ /**
+ * Pass if the page title is the given string.
+ *
+ * @param $title
+ * The string the title should be.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertTitle($title, $message = '', $group = 'Other') {
+ $actual = (string) current($this->xpath('//title'));
+ if (!$message) {
+ $message = t('Page title @actual is equal to @expected.', array(
+ '@actual' => var_export($actual, TRUE),
+ '@expected' => var_export($title, TRUE),
+ ));
+ }
+ return $this->assertEqual($actual, $title, $message, $group);
+ }
+
+ /**
+ * Pass if the page title is not the given string.
+ *
+ * @param $title
+ * The string the title should not be.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoTitle($title, $message = '', $group = 'Other') {
+ $actual = (string) current($this->xpath('//title'));
+ if (!$message) {
+ $message = t('Page title @actual is not equal to @unexpected.', array(
+ '@actual' => var_export($actual, TRUE),
+ '@unexpected' => var_export($title, TRUE),
+ ));
+ }
+ return $this->assertNotEqual($actual, $title, $message, $group);
+ }
+
+ /**
+ * Asserts themed output.
+ *
+ * @param $callback
+ * The name of the theme function to invoke; e.g. 'links' for theme_links().
+ * @param $variables
+ * An array of variables to pass to the theme function.
+ * @param $expected
+ * The expected themed output string.
+ * @param $message
+ * (optional) A message to display with the assertion. Do not translate
+ * messages: use format_string() to embed variables in the message text, not
+ * t(). If left blank, a default message will be displayed.
+ * @param $group
+ * (optional) The group this message is in, which is displayed in a column
+ * in test output. Use 'Debug' to indicate this is debugging output. Do not
+ * translate this string. Defaults to 'Other'; most tests do not override
+ * this default.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertThemeOutput($callback, array $variables = array(), $expected, $message = '', $group = 'Other') {
+ $output = theme($callback, $variables);
+ $this->verbose('Variables:' . '<pre>' . check_plain(var_export($variables, TRUE)) . '</pre>'
+ . '<hr />' . 'Result:' . '<pre>' . check_plain(var_export($output, TRUE)) . '</pre>'
+ . '<hr />' . 'Expected:' . '<pre>' . check_plain(var_export($expected, TRUE)) . '</pre>'
+ . '<hr />' . $output
+ );
+ if (!$message) {
+ $message = '%callback rendered correctly.';
+ }
+ $message = format_string($message, array('%callback' => 'theme_' . $callback . '()'));
+ return $this->assertIdentical($output, $expected, $message, $group);
+ }
+
+ /**
+ * Asserts that a field exists in the current page by the given XPath.
+ *
+ * @param $xpath
+ * XPath used to find the field.
+ * @param $value
+ * (optional) Value of the field to assert.
+ * @param $message
+ * (optional) Message to display.
+ * @param $group
+ * (optional) The group this message belongs to.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertFieldByXPath($xpath, $value = NULL, $message = '', $group = 'Other') {
+ $fields = $this->xpath($xpath);
+
+ // If value specified then check array for match.
+ $found = TRUE;
+ if (isset($value)) {
+ $found = FALSE;
+ if ($fields) {
+ foreach ($fields as $field) {
+ if (isset($field['value']) && $field['value'] == $value) {
+ // Input element with correct value.
+ $found = TRUE;
+ }
+ elseif (isset($field->option)) {
+ // Select element found.
+ if ($this->getSelectedItem($field) == $value) {
+ $found = TRUE;
+ }
+ else {
+ // No item selected so use first item.
+ $items = $this->getAllOptions($field);
+ if (!empty($items) && $items[0]['value'] == $value) {
+ $found = TRUE;
+ }
+ }
+ }
+ elseif ((string) $field == $value) {
+ // Text area with correct text.
+ $found = TRUE;
+ }
+ }
+ }
+ }
+ return $this->assertTrue($fields && $found, $message, $group);
+ }
+
+ /**
+ * Get the selected value from a select field.
+ *
+ * @param $element
+ * SimpleXMLElement select element.
+ * @return
+ * The selected value or FALSE.
+ */
+ protected function getSelectedItem(SimpleXMLElement $element) {
+ foreach ($element->children() as $item) {
+ if (isset($item['selected'])) {
+ return $item['value'];
+ }
+ elseif ($item->getName() == 'optgroup') {
+ if ($value = $this->getSelectedItem($item)) {
+ return $value;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Asserts that a field does not exist in the current page by the given XPath.
+ *
+ * @param $xpath
+ * XPath used to find the field.
+ * @param $value
+ * (optional) Value of the field to assert.
+ * @param $message
+ * (optional) Message to display.
+ * @param $group
+ * (optional) The group this message belongs to.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoFieldByXPath($xpath, $value = NULL, $message = '', $group = 'Other') {
+ $fields = $this->xpath($xpath);
+
+ // If value specified then check array for match.
+ $found = TRUE;
+ if (isset($value)) {
+ $found = FALSE;
+ if ($fields) {
+ foreach ($fields as $field) {
+ if ($field['value'] == $value) {
+ $found = TRUE;
+ }
+ }
+ }
+ }
+ return $this->assertFalse($fields && $found, $message, $group);
+ }
+
+ /**
+ * Asserts that a field exists in the current page with the given name and value.
+ *
+ * @param $name
+ * Name of field to assert.
+ * @param $value
+ * Value of the field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertFieldByName($name, $value = NULL, $message = NULL) {
+ if (!isset($message)) {
+ if (!isset($value)) {
+ $message = t('Found field with name @name', array(
+ '@name' => var_export($name, TRUE),
+ ));
+ }
+ else {
+ $message = t('Found field with name @name and value @value', array(
+ '@name' => var_export($name, TRUE),
+ '@value' => var_export($value, TRUE),
+ ));
+ }
+ }
+ return $this->assertFieldByXPath($this->constructFieldXpath('name', $name), $value, $message, t('Browser'));
+ }
+
+ /**
+ * Asserts that a field does not exist with the given name and value.
+ *
+ * @param $name
+ * Name of field to assert.
+ * @param $value
+ * Value of the field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoFieldByName($name, $value = '', $message = '') {
+ return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $name), $value, $message ? $message : t('Did not find field by name @name', array('@name' => $name)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a field exists in the current page with the given id and value.
+ *
+ * @param $id
+ * Id of field to assert.
+ * @param $value
+ * Value of the field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertFieldById($id, $value = '', $message = '') {
+ return $this->assertFieldByXPath($this->constructFieldXpath('id', $id), $value, $message ? $message : t('Found field by id @id', array('@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a field does not exist with the given id and value.
+ *
+ * @param $id
+ * Id of field to assert.
+ * @param $value
+ * Value of the field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoFieldById($id, $value = '', $message = '') {
+ return $this->assertNoFieldByXPath($this->constructFieldXpath('id', $id), $value, $message ? $message : t('Did not find field by id @id', array('@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a checkbox field in the current page is checked.
+ *
+ * @param $id
+ * Id of field to assert.
+ * @param $message
+ * Message to display.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertFieldChecked($id, $message = '') {
+ $elements = $this->xpath('//input[@id=:id]', array(':id' => $id));
+ return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is checked.', array('@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a checkbox field in the current page is not checked.
+ *
+ * @param $id
+ * Id of field to assert.
+ * @param $message
+ * Message to display.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoFieldChecked($id, $message = '') {
+ $elements = $this->xpath('//input[@id=:id]', array(':id' => $id));
+ return $this->assertTrue(isset($elements[0]) && empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is not checked.', array('@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a select option in the current page is checked.
+ *
+ * @param $id
+ * Id of select field to assert.
+ * @param $option
+ * Option to assert.
+ * @param $message
+ * Message to display.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ *
+ * @todo $id is unusable. Replace with $name.
+ */
+ protected function assertOptionSelected($id, $option, $message = '') {
+ $elements = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => $id, ':option' => $option));
+ return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : t('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a select option in the current page is not checked.
+ *
+ * @param $id
+ * Id of select field to assert.
+ * @param $option
+ * Option to assert.
+ * @param $message
+ * Message to display.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoOptionSelected($id, $option, $message = '') {
+ $elements = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => $id, ':option' => $option));
+ return $this->assertTrue(isset($elements[0]) && empty($elements[0]['selected']), $message ? $message : t('Option @option for field @id is not selected.', array('@option' => $option, '@id' => $id)), t('Browser'));
+ }
+
+ /**
+ * Asserts that a field exists with the given name or id.
+ *
+ * @param $field
+ * Name or id of field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertField($field, $message = '', $group = 'Other') {
+ return $this->assertFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), NULL, $message, $group);
+ }
+
+ /**
+ * Asserts that a field does not exist with the given name or id.
+ *
+ * @param $field
+ * Name or id of field to assert.
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoField($field, $message = '', $group = 'Other') {
+ return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), NULL, $message, $group);
+ }
+
+ /**
+ * Asserts that each HTML ID is used for just a single element.
+ *
+ * @param $message
+ * Message to display.
+ * @param $group
+ * The group this message belongs to.
+ * @param $ids_to_skip
+ * An optional array of ids to skip when checking for duplicates. It is
+ * always a bug to have duplicate HTML IDs, so this parameter is to enable
+ * incremental fixing of core code. Whenever a test passes this parameter,
+ * it should add a "todo" comment above the call to this function explaining
+ * the legacy bug that the test wishes to ignore and including a link to an
+ * issue that is working to fix that legacy bug.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertNoDuplicateIds($message = '', $group = 'Other', $ids_to_skip = array()) {
+ $status = TRUE;
+ foreach ($this->xpath('//*[@id]') as $element) {
+ $id = (string) $element['id'];
+ if (isset($seen_ids[$id]) && !in_array($id, $ids_to_skip)) {
+ $this->fail(t('The HTML ID %id is unique.', array('%id' => $id)), $group);
+ $status = FALSE;
+ }
+ $seen_ids[$id] = TRUE;
+ }
+ return $this->assert($status, $message, $group);
+ }
+
+ /**
+ * Helper function: construct an XPath for the given set of attributes and value.
+ *
+ * @param $attribute
+ * Field attributes.
+ * @param $value
+ * Value of field.
+ * @return
+ * XPath for specified values.
+ */
+ protected function constructFieldXpath($attribute, $value) {
+ $xpath = '//textarea[@' . $attribute . '=:value]|//input[@' . $attribute . '=:value]|//select[@' . $attribute . '=:value]';
+ return $this->buildXPathQuery($xpath, array(':value' => $value));
+ }
+
+ /**
+ * Asserts the page responds with the specified response code.
+ *
+ * @param $code
+ * Response code. For example 200 is a successful page request. For a list
+ * of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
+ * @param $message
+ * Message to display.
+ * @return
+ * Assertion result.
+ */
+ protected function assertResponse($code, $message = '') {
+ $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+ $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
+ return $this->assertTrue($match, $message ? $message : t('HTTP response expected !code, actual !curl_code', array('!code' => $code, '!curl_code' => $curl_code)), t('Browser'));
+ }
+
+ /**
+ * Asserts the page did not return the specified response code.
+ *
+ * @param $code
+ * Response code. For example 200 is a successful page request. For a list
+ * of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
+ * @param $message
+ * Message to display.
+ *
+ * @return
+ * Assertion result.
+ */
+ protected function assertNoResponse($code, $message = '') {
+ $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+ $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
+ return $this->assertFalse($match, $message ? $message : t('HTTP response not expected !code, actual !curl_code', array('!code' => $code, '!curl_code' => $curl_code)), t('Browser'));
+ }
+
+ /**
+ * Asserts that the most recently sent e-mail message has the given value.
+ *
+ * The field in $name must have the content described in $value.
+ *
+ * @param $name
+ * Name of field or message property to assert. Examples: subject, body, id, ...
+ * @param $value
+ * Value of the field to assert.
+ * @param $message
+ * Message to display.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertMail($name, $value = '', $message = '') {
+ $captured_emails = variable_get('drupal_test_email_collector', array());
+ $email = end($captured_emails);
+ return $this->assertTrue($email && isset($email[$name]) && $email[$name] == $value, $message, t('E-mail'));
+ }
+
+ /**
+ * Asserts that the most recently sent e-mail message has the string in it.
+ *
+ * @param $field_name
+ * Name of field or message property to assert: subject, body, id, ...
+ * @param $string
+ * String to search for.
+ * @param $email_depth
+ * Number of emails to search for string, starting with most recent.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertMailString($field_name, $string, $email_depth) {
+ $mails = $this->drupalGetMails();
+ $string_found = FALSE;
+ for ($i = sizeof($mails) -1; $i >= sizeof($mails) - $email_depth && $i >= 0; $i--) {
+ $mail = $mails[$i];
+ // Normalize whitespace, as we don't know what the mail system might have
+ // done. Any run of whitespace becomes a single space.
+ $normalized_mail = preg_replace('/\s+/', ' ', $mail[$field_name]);
+ $normalized_string = preg_replace('/\s+/', ' ', $string);
+ $string_found = (FALSE !== strpos($normalized_mail, $normalized_string));
+ if ($string_found) {
+ break;
+ }
+ }
+ return $this->assertTrue($string_found, t('Expected text found in @field of email message: "@expected".', array('@field' => $field_name, '@expected' => $string)));
+ }
+
+ /**
+ * Asserts that the most recently sent e-mail message has the pattern in it.
+ *
+ * @param $field_name
+ * Name of field or message property to assert: subject, body, id, ...
+ * @param $regex
+ * Pattern to search for.
+ *
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function assertMailPattern($field_name, $regex, $message) {
+ $mails = $this->drupalGetMails();
+ $mail = end($mails);
+ $regex_found = preg_match("/$regex/", $mail[$field_name]);
+ return $this->assertTrue($regex_found, t('Expected text found in @field of email message: "@expected".', array('@field' => $field_name, '@expected' => $regex)));
+ }
+
+ /**
+ * Outputs to verbose the most recent $count emails sent.
+ *
+ * @param $count
+ * Optional number of emails to output.
+ */
+ protected function verboseEmail($count = 1) {
+ $mails = $this->drupalGetMails();
+ for ($i = sizeof($mails) -1; $i >= sizeof($mails) - $count && $i >= 0; $i--) {
+ $mail = $mails[$i];
+ $this->verbose(t('Email:') . '<pre>' . print_r($mail, TRUE) . '</pre>');
+ }
+ }
+}
+
+/**
+ * Logs verbose message in a text file.
+ *
+ * If verbose mode is enabled then page requests will be dumped to a file and
+ * presented on the test result screen. The messages will be placed in a file
+ * located in the simpletest directory in the original file system.
+ *
+ * @param $message
+ * The verbose message to be stored.
+ * @param $original_file_directory
+ * The original file directory, before it was changed for testing purposes.
+ * @param $test_class
+ * The active test case class.
+ *
+ * @return
+ * The ID of the message to be placed in related assertion messages.
+ *
+ * @see DrupalTestCase->originalFileDirectory
+ * @see DrupalWebTestCase->verbose()
+ */
+function simpletest_verbose($message, $original_file_directory = NULL, $test_class = NULL) {
+ static $file_directory = NULL, $class = NULL, $id = 1, $verbose = NULL;
+
+ // Will pass first time during setup phase, and when verbose is TRUE.
+ if (!isset($original_file_directory) && !$verbose) {
+ return FALSE;
+ }
+
+ if ($message && $file_directory) {
+ $message = '<hr />ID #' . $id . ' (<a href="' . $class . '-' . ($id - 1) . '.html">Previous</a> | <a href="' . $class . '-' . ($id + 1) . '.html">Next</a>)<hr />' . $message;
+ file_put_contents($file_directory . "/simpletest/verbose/$class-$id.html", $message, FILE_APPEND);
+ return $id++;
+ }
+
+ if ($original_file_directory) {
+ $file_directory = $original_file_directory;
+ $class = $test_class;
+ $verbose = variable_get('simpletest_verbose', TRUE);
+ $directory = $file_directory . '/simpletest/verbose';
+ $writable = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+ if ($writable && !file_exists($directory . '/.htaccess')) {
+ file_put_contents($directory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n");
+ }
+ return $writable;
+ }
+ return FALSE;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/README.txt b/kolab.org/www/drupal-7.26/modules/simpletest/files/README.txt
new file mode 100644
index 0000000..680e7fe
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/README.txt
@@ -0,0 +1,4 @@
+These files are useful in tests that upload files or otherwise need to
+manipulate files, in which case they are copied to the files directory as
+specified in the site settings. Dummy files can also be generated by tests in
+order to save space.
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css
new file mode 100644
index 0000000..c47e842
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css
@@ -0,0 +1,80 @@
+/*
+* A sample css file, designed to test the effectiveness and stability
+* of function <code>drupal_load_stylesheet_content()</code>.
+*
+*/
+/*
+A large comment block to test for segfaults and speed. This is 60K a's. Extreme but useful to demonstrate flaws in comment striping regexp. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/
+.test1 { display:block;}
+
+/* A multiline IE-mac hack (v.2) taken fron Zen theme*/
+/* Hides from IE-mac \*/
+html .clear-block {
+ height: 1%;
+}
+.clear-block {
+ display: block;
+ font:italic bold 12px/30px Georgia, serif;
+}
+
+/* End hide from IE-mac */
+.test2 { display:block; }
+
+/* v1 of the commented backslash hack. This \ character between rules appears to have the effect
+that macIE5 ignores the following rule. Odd, but extremely useful. */
+.bkslshv1 { background-color: #C00; }
+.test3 { display:block; }
+
+/**************** A multiline, multistar comment ***************
+****************************************************************/
+.test4 { display:block;}
+
+/**************************************/
+.comment-in-double-quotes:before {
+ content: "/* ";
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-double-quotes:after {
+ content: " */";
+}
+/**************************************/
+.comment-in-single-quotes:before {
+ content: '/*';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-single-quotes:after {
+ content: '*/';
+}
+/**************************************/
+.comment-in-mixed-quotes:before {
+ content: '"/*"';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-mixed-quotes:after {
+ content: "'*/'";
+}
+/**************************************/
+.comment-in-quotes-with-escaped:before {
+ content: '/* \" \' */';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-quotes-with-escaped:after {
+ content: "*/ \" \ '";
+}
+/************************************/
+/*
+"This has to go"
+'This has to go'
+*/
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css
new file mode 100644
index 0000000..1feb8f1
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css
@@ -0,0 +1 @@
+.test1{display:block;}html .clear-block{height:1%;}.clear-block{display:block;font:italic bold 12px/30px Georgia,serif;}.test2{display:block;}.bkslshv1{background-color:#C00;}.test3{display:block;}.test4{display:block;}.comment-in-double-quotes:before{content:"/* ";}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-double-quotes:after{content:" */";}.comment-in-single-quotes:before{content:'/*';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-single-quotes:after{content:'*/';}.comment-in-mixed-quotes:before{content:'"/*"';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-mixed-quotes:after{content:"'*/'";}.comment-in-quotes-with-escaped:before{content:'/* \" \' */';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-quotes-with-escaped:after{content:"*/ \" \ '";}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css
new file mode 100644
index 0000000..c47e842
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css
@@ -0,0 +1,80 @@
+/*
+* A sample css file, designed to test the effectiveness and stability
+* of function <code>drupal_load_stylesheet_content()</code>.
+*
+*/
+/*
+A large comment block to test for segfaults and speed. This is 60K a's. Extreme but useful to demonstrate flaws in comment striping regexp. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/
+.test1 { display:block;}
+
+/* A multiline IE-mac hack (v.2) taken fron Zen theme*/
+/* Hides from IE-mac \*/
+html .clear-block {
+ height: 1%;
+}
+.clear-block {
+ display: block;
+ font:italic bold 12px/30px Georgia, serif;
+}
+
+/* End hide from IE-mac */
+.test2 { display:block; }
+
+/* v1 of the commented backslash hack. This \ character between rules appears to have the effect
+that macIE5 ignores the following rule. Odd, but extremely useful. */
+.bkslshv1 { background-color: #C00; }
+.test3 { display:block; }
+
+/**************** A multiline, multistar comment ***************
+****************************************************************/
+.test4 { display:block;}
+
+/**************************************/
+.comment-in-double-quotes:before {
+ content: "/* ";
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-double-quotes:after {
+ content: " */";
+}
+/**************************************/
+.comment-in-single-quotes:before {
+ content: '/*';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-single-quotes:after {
+ content: '*/';
+}
+/**************************************/
+.comment-in-mixed-quotes:before {
+ content: '"/*"';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-mixed-quotes:after {
+ content: "'*/'";
+}
+/**************************************/
+.comment-in-quotes-with-escaped:before {
+ content: '/* \" \' */';
+}
+.this_rule_must_stay {
+ color: #F00;
+ background-color: #FFF;
+}
+.comment-in-quotes-with-escaped:after {
+ content: "*/ \" \ '";
+}
+/************************************/
+/*
+"This has to go"
+'This has to go'
+*/
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css
new file mode 100644
index 0000000..87afcb3
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css
@@ -0,0 +1,30 @@
+
+
+@import "import1.css";
+@import "import2.css";
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css
new file mode 100644
index 0000000..698d9aa
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css
@@ -0,0 +1,6 @@
+ul,select{font:1em/160% Verdana,sans-serif;color:#494949;}.ui-icon{background-image:url(images/icon.png);}
+p,select{font:1em/160% Verdana,sans-serif;color:#494949;}
+body{margin:0;padding:0;background:#edf5fa;font:76%/170% Verdana,sans-serif;color:#494949;}.this .is .a .test{font:1em/100% Verdana,sans-serif;color:#494949;}.this
+.is
+.a
+.test{font:1em/100% Verdana,sans-serif;color:#494949;}textarea,select{font:1em/160% Verdana,sans-serif;color:#494949;}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css
new file mode 100644
index 0000000..19323c1
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css
@@ -0,0 +1,40 @@
+
+
+
+ul, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+.ui-icon{background-image: url(images/icon.png);}
+
+p, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css
new file mode 100644
index 0000000..620360a
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css
@@ -0,0 +1,69 @@
+
+/**
+ * @file Basic css that does not use import
+ */
+
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+
+/**
+ * CSS spec says that all whitespace is valid whitespace, so this selector
+ * should be just as good as the one above.
+ */
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+some :pseudo .thing {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
+ -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
+}
+
+::-moz-selection {
+ background: #000;
+ color:#fff;
+
+}
+::selection {
+ background: #000;
+ color: #fff;
+}
+
+@media print {
+ * {
+ background: #000 !important;
+ color: #fff !important;
+ }
+ @page {
+ margin: 0.5cm;
+ }
+}
+
+@media screen and (max-device-width: 480px) {
+ background: #000;
+ color: #fff;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css
new file mode 100644
index 0000000..c7bb9dc
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css
@@ -0,0 +1,4 @@
+body{margin:0;padding:0;background:#edf5fa;font:76%/170% Verdana,sans-serif;color:#494949;}.this .is .a .test{font:1em/100% Verdana,sans-serif;color:#494949;}.this
+.is
+.a
+.test{font:1em/100% Verdana,sans-serif;color:#494949;}some :pseudo .thing{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;filter:progid:DXImageTransform.Microsoft.Shadow(color=#000000,direction='180',strength='10');-ms-filter:"progid:DXImageTransform.Microsoft.Shadow(color=#000000,direction='180',strength='10')";}::-moz-selection{background:#000;color:#fff;}::selection{background:#000;color:#fff;}@media print{*{background:#000 !important;color:#fff !important;}@page{margin:0.5cm;}}@media screen and (max-device-width:480px){background:#000;color:#fff;}textarea,select{font:1em/160% Verdana,sans-serif;color:#494949;}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css
new file mode 100644
index 0000000..620360a
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css
@@ -0,0 +1,69 @@
+
+/**
+ * @file Basic css that does not use import
+ */
+
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+
+/**
+ * CSS spec says that all whitespace is valid whitespace, so this selector
+ * should be just as good as the one above.
+ */
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+some :pseudo .thing {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
+ -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
+}
+
+::-moz-selection {
+ background: #000;
+ color:#fff;
+
+}
+::selection {
+ background: #000;
+ color: #fff;
+}
+
+@media print {
+ * {
+ background: #000 !important;
+ color: #fff !important;
+ }
+ @page {
+ margin: 0.5cm;
+ }
+}
+
+@media screen and (max-device-width: 480px) {
+ background: #000;
+ color: #fff;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css
new file mode 100644
index 0000000..d90ecbc
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css
@@ -0,0 +1,29 @@
+
+
+@import "../import1.css";
+@import "../import2.css";
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css
new file mode 100644
index 0000000..aba3b21
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css
@@ -0,0 +1,6 @@
+ul,select{font:1em/160% Verdana,sans-serif;color:#494949;}.ui-icon{background-image:url(../images/icon.png);}
+p,select{font:1em/160% Verdana,sans-serif;color:#494949;}
+body{margin:0;padding:0;background:#edf5fa;font:76%/170% Verdana,sans-serif;color:#494949;}.this .is .a .test{font:1em/100% Verdana,sans-serif;color:#494949;}.this
+.is
+.a
+.test{font:1em/100% Verdana,sans-serif;color:#494949;}textarea,select{font:1em/160% Verdana,sans-serif;color:#494949;}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css
new file mode 100644
index 0000000..710d8f1
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css
@@ -0,0 +1,39 @@
+
+
+
+ul, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+.ui-icon{background-image: url(../images/icon.png);}
+
+p, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #edf5fa;
+ font: 76%/170% Verdana, sans-serif;
+ color: #494949;
+}
+
+.this .is .a .test {
+ font: 1em/100% Verdana, sans-serif;
+ color: #494949;
+}
+.this
+.is
+.a
+.test {
+font: 1em/100% Verdana, sans-serif;
+color: #494949;
+}
+
+textarea, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import1.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import1.css
new file mode 100644
index 0000000..3d5842e
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import1.css
@@ -0,0 +1,6 @@
+
+ul, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
+.ui-icon{background-image: url(images/icon.png);} \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import2.css b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import2.css
new file mode 100644
index 0000000..367eb57
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/css_test_files/import2.css
@@ -0,0 +1,5 @@
+
+p, select {
+ font: 1em/160% Verdana, sans-serif;
+ color: #494949;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/html-1.txt b/kolab.org/www/drupal-7.26/modules/simpletest/files/html-1.txt
new file mode 100644
index 0000000..494470d
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/html-1.txt
@@ -0,0 +1 @@
+<h1>SimpleTest HTML</h1> \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/html-2.html b/kolab.org/www/drupal-7.26/modules/simpletest/files/html-2.html
new file mode 100644
index 0000000..494470d
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/html-2.html
@@ -0,0 +1 @@
+<h1>SimpleTest HTML</h1> \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/image-1.png b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-1.png
new file mode 100644
index 0000000..09e64d6
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-1.png
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/image-2.jpg b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-2.jpg
new file mode 100644
index 0000000..ace07d0
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-2.jpg
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.gif b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.gif
new file mode 100644
index 0000000..432990b
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.gif
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.jpg b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.jpg
new file mode 100644
index 0000000..de4eace
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.jpg
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.png b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.png
new file mode 100644
index 0000000..39c0419
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/image-test.png
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-1.txt b/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-1.txt
new file mode 100644
index 0000000..efd44fd
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-1.txt
@@ -0,0 +1,3 @@
+<script>
+alert('SimpleTest PHP was executed!');
+</script>
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-2.script b/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-2.script
new file mode 100644
index 0000000..e0206ba
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/javascript-2.script
@@ -0,0 +1,3 @@
+<script>
+alert('SimpleTest PHP was executed!');
+</script> \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/php-1.txt b/kolab.org/www/drupal-7.26/modules/simpletest/files/php-1.txt
new file mode 100644
index 0000000..52788b6
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/php-1.txt
@@ -0,0 +1,3 @@
+<?php
+print 'SimpleTest PHP was executed!';
+?>
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/php-2.php b/kolab.org/www/drupal-7.26/modules/simpletest/files/php-2.php
new file mode 100644
index 0000000..615a8d7
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/php-2.php
@@ -0,0 +1,2 @@
+<?php
+print 'SimpleTest PHP was executed!';
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-1.txt b/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-1.txt
new file mode 100644
index 0000000..22017e9
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-1.txt
@@ -0,0 +1 @@
+SELECT invalid_field FROM {invalid_table} \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-2.sql b/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-2.sql
new file mode 100644
index 0000000..22017e9
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/files/sql-2.sql
@@ -0,0 +1 @@
+SELECT invalid_field FROM {invalid_table} \ No newline at end of file
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php b/kolab.org/www/drupal-7.26/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php
new file mode 100644
index 0000000..0292956
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\simpletest\Tests;
+
+class PSR0WebTest extends \DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'PSR0 web test',
+ 'description' => 'We want to assert that this PSR-0 test case is being discovered.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function testArithmetics() {
+ $this->assert(1 + 1 == 2, '1 + 1 == 2');
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.api.php b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.api.php
new file mode 100644
index 0000000..d262ad6
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.api.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the SimpleTest module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter the list of tests.
+ *
+ * @param $groups
+ * A two dimension array, the first key is the test group (as defined in
+ * getInfo) the second is the name of the class and the value is the return
+ * value of the getInfo method.
+ */
+function hook_simpletest_alter(&$groups) {
+ // An alternative session handler module would not want to run the original
+ // Session HTTPS handling test because it checks the sessions table in the
+ // database.
+ unset($groups['Session']['testHttpsSession']);
+}
+
+/**
+ * A test group has started.
+ *
+ * This hook is called just once at the beginning of a test group.
+ */
+function hook_test_group_started() {
+}
+
+/**
+ * A test group has finished.
+ *
+ * This hook is called just once at the end of a test group.
+ */
+function hook_test_group_finished() {
+}
+
+/**
+ * An individual test has finished.
+ *
+ * This hook is called when an individual test has finished.
+ *
+ * @param
+ * $results The results of the test as gathered by DrupalWebTestCase.
+ *
+ * @see DrupalWebTestCase->results
+ */
+function hook_test_finished($results) {
+}
+
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.css b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.css
new file mode 100644
index 0000000..0cf9aaa
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.css
@@ -0,0 +1,89 @@
+
+/* Test Table */
+#simpletest-form-table th.select-all {
+ width: 1em;
+}
+th.simpletest_test {
+ width: 16em;
+}
+
+.simpletest-image {
+ display: inline-block;
+ cursor: pointer;
+ width: 1em;
+}
+.simpletest-group-label label {
+ display: inline;
+ font-weight: bold;
+}
+.simpletest-test-label label {
+ margin-left: 1em; /* LTR */
+}
+.simpletest-test-description .description {
+ margin: 0;
+}
+#simpletest-form-table tr td {
+ background-color: white;
+ color: #494949;
+}
+#simpletest-form-table tr.simpletest-group td {
+ background-color: #EDF5FA;
+ color: #494949;
+}
+
+table#simpletest-form-table tr.simpletest-group label {
+ display: inline;
+}
+
+div.message > div.item-list {
+ font-weight: normal;
+}
+
+div.simpletest-pass {
+ color: #33a333;
+}
+.simpletest-fail {
+ color: #981010;
+}
+
+tr.simpletest-pass.odd {
+ background-color: #b6ffb6;
+}
+tr.simpletest-pass.even {
+ background-color: #9bff9b;
+}
+tr.simpletest-fail.odd {
+ background-color: #ffc9c9;
+}
+tr.simpletest-fail.even {
+ background-color: #ffacac;
+}
+tr.simpletest-exception.odd {
+ background-color: #f4ea71;
+}
+tr.simpletest-exception.even {
+ background-color: #f5e742;
+}
+tr.simpletest-debug.odd {
+ background-color: #eee;
+}
+tr.simpletest-debug.even {
+ background-color: #fff;
+}
+
+a.simpletest-collapse {
+ height: 0;
+ width: 0;
+ top: -99em;
+ position: absolute;
+}
+a.simpletest-collapse:focus,
+a.simpletest-collapse:hover {
+ font-size: 80%;
+ top: 0px;
+ height: auto;
+ width: auto;
+ overflow: visible;
+ position: relative;
+ z-index: 1000;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.info b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.info
new file mode 100644
index 0000000..7a5fd8c
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.info
@@ -0,0 +1,62 @@
+name = Testing
+description = Provides a framework for unit and functional testing.
+package = Core
+version = VERSION
+core = 7.x
+files[] = simpletest.test
+files[] = drupal_web_test_case.php
+configure = admin/config/development/testing/settings
+
+; Tests in tests directory.
+files[] = tests/actions.test
+files[] = tests/ajax.test
+files[] = tests/batch.test
+files[] = tests/bootstrap.test
+files[] = tests/cache.test
+files[] = tests/common.test
+files[] = tests/database_test.test
+files[] = tests/entity_crud_hook_test.test
+files[] = tests/entity_query.test
+files[] = tests/error.test
+files[] = tests/file.test
+files[] = tests/filetransfer.test
+files[] = tests/form.test
+files[] = tests/graph.test
+files[] = tests/image.test
+files[] = tests/lock.test
+files[] = tests/mail.test
+files[] = tests/menu.test
+files[] = tests/module.test
+files[] = tests/pager.test
+files[] = tests/password.test
+files[] = tests/path.test
+files[] = tests/registry.test
+files[] = tests/schema.test
+files[] = tests/session.test
+files[] = tests/tablesort.test
+files[] = tests/theme.test
+files[] = tests/unicode.test
+files[] = tests/update.test
+files[] = tests/xmlrpc.test
+files[] = tests/upgrade/upgrade.test
+files[] = tests/upgrade/upgrade.comment.test
+files[] = tests/upgrade/upgrade.filter.test
+files[] = tests/upgrade/upgrade.forum.test
+files[] = tests/upgrade/upgrade.locale.test
+files[] = tests/upgrade/upgrade.menu.test
+files[] = tests/upgrade/upgrade.node.test
+files[] = tests/upgrade/upgrade.taxonomy.test
+files[] = tests/upgrade/upgrade.trigger.test
+files[] = tests/upgrade/upgrade.translatable.test
+files[] = tests/upgrade/upgrade.upload.test
+files[] = tests/upgrade/upgrade.user.test
+files[] = tests/upgrade/update.aggregator.test
+files[] = tests/upgrade/update.trigger.test
+files[] = tests/upgrade/update.field.test
+files[] = tests/upgrade/update.user.test
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.install b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.install
new file mode 100644
index 0000000..6c6f569
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.install
@@ -0,0 +1,182 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the simpletest module.
+ */
+
+/**
+ * Minimum value of PHP memory_limit for SimpleTest.
+ */
+define('SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT', '64M');
+
+/**
+ * Implements hook_requirements().
+ */
+function simpletest_requirements($phase) {
+ $requirements = array();
+ $t = get_t();
+
+ $has_curl = function_exists('curl_init');
+ $has_hash = function_exists('hash_hmac');
+ $has_domdocument = method_exists('DOMDocument', 'loadHTML');
+ $open_basedir = ini_get('open_basedir');
+
+ $requirements['curl'] = array(
+ 'title' => $t('cURL'),
+ 'value' => $has_curl ? $t('Enabled') : $t('Not found'),
+ );
+ if (!$has_curl) {
+ $requirements['curl']['severity'] = REQUIREMENT_ERROR;
+ $requirements['curl']['description'] = $t('The testing framework could not be installed because the PHP <a href="@curl_url">cURL</a> library is not available.', array('@curl_url' => 'http://php.net/manual/en/curl.setup.php'));
+ }
+ $requirements['hash'] = array(
+ 'title' => $t('hash'),
+ 'value' => $has_hash ? $t('Enabled') : $t('Not found'),
+ );
+ if (!$has_hash) {
+ $requirements['hash']['severity'] = REQUIREMENT_ERROR;
+ $requirements['hash']['description'] = $t('The testing framework could not be installed because the PHP <a href="@hash_url">hash</a> extension is disabled.', array('@hash_url' => 'http://php.net/manual/en/book.hash.php'));
+ }
+
+ $requirements['php_domdocument'] = array(
+ 'title' => $t('PHP DOMDocument class'),
+ 'value' => $has_domdocument ? $t('Enabled') : $t('Not found'),
+ );
+ if (!$has_domdocument) {
+ $requirements['php_domdocument']['severity'] = REQUIREMENT_ERROR;
+ $requirements['php_domdocument']['description'] = $t('The testing framework requires the DOMDocument class to be available. Check the configure command at the <a href="@link-phpinfo">PHP info page</a>.', array('@link-phpinfo' => url('admin/reports/status/php')));
+ }
+
+ // SimpleTest currently needs 2 cURL options which are incompatible with
+ // having PHP's open_basedir restriction set.
+ // See http://drupal.org/node/674304.
+ $requirements['php_open_basedir'] = array(
+ 'title' => $t('PHP open_basedir restriction'),
+ 'value' => $open_basedir ? $t('Enabled') : $t('Disabled'),
+ );
+ if ($open_basedir) {
+ $requirements['php_open_basedir']['severity'] = REQUIREMENT_ERROR;
+ $requirements['php_open_basedir']['description'] = $t('The testing framework requires the PHP <a href="@open_basedir-url">open_basedir</a> restriction to be disabled. Check your webserver configuration or contact your web host.', array('@open_basedir-url' => 'http://php.net/manual/en/ini.core.php#ini.open-basedir'));
+ }
+
+ // Check the current memory limit. If it is set too low, SimpleTest will fail
+ // to load all tests and throw a fatal error.
+ $memory_limit = ini_get('memory_limit');
+ if (!drupal_check_memory_limit(SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, $memory_limit)) {
+ $requirements['php_memory_limit']['severity'] = REQUIREMENT_ERROR;
+ $requirements['php_memory_limit']['description'] = $t('The testing framework requires the PHP memory limit to be at least %memory_minimum_limit. The current value is %memory_limit. <a href="@url">Follow these steps to continue</a>.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, '@url' => 'http://drupal.org/node/207036'));
+ }
+
+ return $requirements;
+}
+
+/**
+ * Implements hook_schema().
+ */
+function simpletest_schema() {
+ $schema['simpletest'] = array(
+ 'description' => 'Stores simpletest messages',
+ 'fields' => array(
+ 'message_id' => array(
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'description' => 'Primary Key: Unique simpletest message ID.',
+ ),
+ 'test_id' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'Test ID, messages belonging to the same ID are reported together',
+ ),
+ 'test_class' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The name of the class that created this message.',
+ ),
+ 'status' => array(
+ 'type' => 'varchar',
+ 'length' => 9,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Message status. Core understands pass, fail, exception.',
+ ),
+ 'message' => array(
+ 'type' => 'text',
+ 'not null' => TRUE,
+ 'description' => 'The message itself.',
+ ),
+ 'message_group' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The message group this message belongs to. For example: warning, browser, user.',
+ ),
+ 'function' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Name of the assertion function or method that created this message.',
+ ),
+ 'line' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'Line number on which the function is called.',
+ ),
+ 'file' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Name of the file where the function is called.',
+ ),
+ ),
+ 'primary key' => array('message_id'),
+ 'indexes' => array(
+ 'reporter' => array('test_class', 'message_id'),
+ ),
+ );
+ $schema['simpletest_test_id'] = array(
+ 'description' => 'Stores simpletest test IDs, used to auto-incrament the test ID so that a fresh test ID is used.',
+ 'fields' => array(
+ 'test_id' => array(
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'description' => 'Primary Key: Unique simpletest ID used to group test results together. Each time a set of tests
+ are run a new test ID is used.',
+ ),
+ 'last_prefix' => array(
+ 'type' => 'varchar',
+ 'length' => 60,
+ 'not null' => FALSE,
+ 'default' => '',
+ 'description' => 'The last database prefix used during testing.',
+ ),
+ ),
+ 'primary key' => array('test_id'),
+ );
+ return $schema;
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function simpletest_uninstall() {
+ drupal_load('module', 'simpletest');
+ simpletest_clean_database();
+
+ // Remove settings variables.
+ variable_del('simpletest_httpauth_method');
+ variable_del('simpletest_httpauth_username');
+ variable_del('simpletest_httpauth_password');
+ variable_del('simpletest_clear_results');
+ variable_del('simpletest_verbose');
+
+ // Remove generated files.
+ file_unmanaged_delete_recursive('public://simpletest');
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.js b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.js
new file mode 100644
index 0000000..2199fed
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.js
@@ -0,0 +1,104 @@
+(function ($) {
+
+/**
+ * Add the cool table collapsing on the testing overview page.
+ */
+Drupal.behaviors.simpleTestMenuCollapse = {
+ attach: function (context, settings) {
+ var timeout = null;
+ // Adds expand-collapse functionality.
+ $('div.simpletest-image').once('simpletest-image', function () {
+ var $this = $(this);
+ var direction = settings.simpleTest[this.id].imageDirection;
+ $this.html(settings.simpleTest.images[direction]);
+
+ // Adds group toggling functionality to arrow images.
+ $this.click(function () {
+ var trs = $this.closest('tbody').children('.' + settings.simpleTest[this.id].testClass);
+ var direction = settings.simpleTest[this.id].imageDirection;
+ var row = direction ? trs.length - 1 : 0;
+
+ // If clicked in the middle of expanding a group, stop so we can switch directions.
+ if (timeout) {
+ clearTimeout(timeout);
+ }
+
+ // Function to toggle an individual row according to the current direction.
+ // We set a timeout of 20 ms until the next row will be shown/hidden to
+ // create a sliding effect.
+ function rowToggle() {
+ if (direction) {
+ if (row >= 0) {
+ $(trs[row]).hide();
+ row--;
+ timeout = setTimeout(rowToggle, 20);
+ }
+ }
+ else {
+ if (row < trs.length) {
+ $(trs[row]).removeClass('js-hide').show();
+ row++;
+ timeout = setTimeout(rowToggle, 20);
+ }
+ }
+ }
+
+ // Kick-off the toggling upon a new click.
+ rowToggle();
+
+ // Toggle the arrow image next to the test group title.
+ $this.html(settings.simpleTest.images[(direction ? 0 : 1)]);
+ settings.simpleTest[this.id].imageDirection = !direction;
+
+ });
+ });
+ }
+};
+
+/**
+ * Select/deselect all the inner checkboxes when the outer checkboxes are
+ * selected/deselected.
+ */
+Drupal.behaviors.simpleTestSelectAll = {
+ attach: function (context, settings) {
+ $('td.simpletest-select-all').once('simpletest-select-all', function () {
+ var testCheckboxes = settings.simpleTest['simpletest-test-group-' + $(this).attr('id')].testNames;
+ var groupCheckbox = $('<input type="checkbox" class="form-checkbox" id="' + $(this).attr('id') + '-select-all" />');
+
+ // Each time a single-test checkbox is checked or unchecked, make sure
+ // that the associated group checkbox gets the right state too.
+ var updateGroupCheckbox = function () {
+ var checkedTests = 0;
+ for (var i = 0; i < testCheckboxes.length; i++) {
+ $('#' + testCheckboxes[i]).each(function () {
+ if (($(this).attr('checked'))) {
+ checkedTests++;
+ }
+ });
+ }
+ $(groupCheckbox).attr('checked', (checkedTests == testCheckboxes.length));
+ };
+
+ // Have the single-test checkboxes follow the group checkbox.
+ groupCheckbox.change(function () {
+ var checked = !!($(this).attr('checked'));
+ for (var i = 0; i < testCheckboxes.length; i++) {
+ $('#' + testCheckboxes[i]).attr('checked', checked);
+ }
+ });
+
+ // Have the group checkbox follow the single-test checkboxes.
+ for (var i = 0; i < testCheckboxes.length; i++) {
+ $('#' + testCheckboxes[i]).change(function () {
+ updateGroupCheckbox();
+ });
+ }
+
+ // Initialize status for the group checkbox correctly.
+ updateGroupCheckbox();
+ $(this).append(groupCheckbox);
+ });
+ }
+};
+
+})(jQuery);
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.module b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.module
new file mode 100644
index 0000000..3103af0
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.module
@@ -0,0 +1,626 @@
+<?php
+
+/**
+ * @file
+ * Provides testing functionality.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function simpletest_help($path, $arg) {
+ switch ($path) {
+ case 'admin/help#simpletest':
+ $output = '';
+ $output .= '<h3>' . t('About') . '</h3>';
+ $output .= '<p>' . t('The Testing module provides a framework for running automated unit tests. It can be used to verify a working state of Drupal before and after any code changes, or as a means for developers to write and execute tests for their modules. For more information, see the online handbook entry for <a href="@simpletest">Testing module</a>.', array('@simpletest' => 'http://drupal.org/documentation/modules/simpletest', '@blocks' => url('admin/structure/block'))) . '</p>';
+ $output .= '<h3>' . t('Uses') . '</h3>';
+ $output .= '<dl>';
+ $output .= '<dt>' . t('Running tests') . '</dt>';
+ $output .= '<dd>' . t('Visit the <a href="@admin-simpletest">Testing page</a> to display a list of available tests. For comprehensive testing, select <em>all</em> tests, or individually select tests for more targeted testing. Note that it might take several minutes for all tests to complete. For more information on creating and modifying your own tests, see the <a href="@simpletest-api">Testing API Documentation</a> in the Drupal handbook.', array('@simpletest-api' => 'http://drupal.org/simpletest', '@admin-simpletest' => url('admin/config/development/testing'))) . '</dd>';
+ $output .= '<dd>' . t('After the tests run, a message will be displayed next to each test group indicating whether tests within it passed, failed, or had exceptions. A pass means that the test returned the expected results, while fail means that it did not. An exception normally indicates an error outside of the test, such as a PHP warning or notice. If there were failures or exceptions, the results will be expanded to show details, and the tests that had failures or exceptions will be indicated in red or pink rows. You can then use these results to refine your code and tests, until all tests pass.') . '</dd>';
+ $output .= '</dl>';
+ return $output;
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function simpletest_menu() {
+ $items['admin/config/development/testing'] = array(
+ 'title' => 'Testing',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('simpletest_test_form'),
+ 'description' => 'Run tests against Drupal core and your active modules. These tests help assure that your site code is working as designed.',
+ 'access arguments' => array('administer unit tests'),
+ 'file' => 'simpletest.pages.inc',
+ 'weight' => -5,
+ );
+ $items['admin/config/development/testing/list'] = array(
+ 'title' => 'List',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ );
+ $items['admin/config/development/testing/settings'] = array(
+ 'title' => 'Settings',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('simpletest_settings_form'),
+ 'access arguments' => array('administer unit tests'),
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'simpletest.pages.inc',
+ );
+ $items['admin/config/development/testing/results/%'] = array(
+ 'title' => 'Test result',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('simpletest_result_form', 5),
+ 'description' => 'View result of tests.',
+ 'access arguments' => array('administer unit tests'),
+ 'file' => 'simpletest.pages.inc',
+ );
+ return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function simpletest_permission() {
+ return array(
+ 'administer unit tests' => array(
+ 'title' => t('Administer tests'),
+ 'restrict access' => TRUE,
+ ),
+ );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function simpletest_theme() {
+ return array(
+ 'simpletest_test_table' => array(
+ 'render element' => 'table',
+ 'file' => 'simpletest.pages.inc',
+ ),
+ 'simpletest_result_summary' => array(
+ 'render element' => 'form',
+ 'file' => 'simpletest.pages.inc',
+ ),
+ );
+}
+
+/**
+ * Implements hook_js_alter().
+ */
+function simpletest_js_alter(&$javascript) {
+ // Since SimpleTest is a special use case for the table select, stick the
+ // SimpleTest JavaScript above the table select.
+ $simpletest = drupal_get_path('module', 'simpletest') . '/simpletest.js';
+ if (array_key_exists($simpletest, $javascript) && array_key_exists('misc/tableselect.js', $javascript)) {
+ $javascript[$simpletest]['weight'] = $javascript['misc/tableselect.js']['weight'] - 1;
+ }
+}
+
+function _simpletest_format_summary_line($summary) {
+ $args = array(
+ '@pass' => format_plural(isset($summary['#pass']) ? $summary['#pass'] : 0, '1 pass', '@count passes'),
+ '@fail' => format_plural(isset($summary['#fail']) ? $summary['#fail'] : 0, '1 fail', '@count fails'),
+ '@exception' => format_plural(isset($summary['#exception']) ? $summary['#exception'] : 0, '1 exception', '@count exceptions'),
+ );
+ if (!$summary['#debug']) {
+ return t('@pass, @fail, and @exception', $args);
+ }
+ $args['@debug'] = format_plural(isset($summary['#debug']) ? $summary['#debug'] : 0, '1 debug message', '@count debug messages');
+ return t('@pass, @fail, @exception, and @debug', $args);
+}
+
+/**
+ * Actually runs tests.
+ *
+ * @param $test_list
+ * List of tests to run.
+ * @param $reporter
+ * Which reporter to use. Allowed values are: text, xml, html and drupal,
+ * drupal being the default.
+ */
+function simpletest_run_tests($test_list, $reporter = 'drupal') {
+ $test_id = db_insert('simpletest_test_id')
+ ->useDefaults(array('test_id'))
+ ->execute();
+
+ // Clear out the previous verbose files.
+ file_unmanaged_delete_recursive('public://simpletest/verbose');
+
+ // Get the info for the first test being run.
+ $first_test = array_shift($test_list);
+ $first_instance = new $first_test();
+ array_unshift($test_list, $first_test);
+ $info = $first_instance->getInfo();
+
+ $batch = array(
+ 'title' => t('Running tests'),
+ 'operations' => array(
+ array('_simpletest_batch_operation', array($test_list, $test_id)),
+ ),
+ 'finished' => '_simpletest_batch_finished',
+ 'progress_message' => '',
+ 'css' => array(drupal_get_path('module', 'simpletest') . '/simpletest.css'),
+ 'init_message' => t('Processing test @num of @max - %test.', array('%test' => $info['name'], '@num' => '1', '@max' => count($test_list))),
+ );
+ batch_set($batch);
+
+ module_invoke_all('test_group_started');
+
+ return $test_id;
+}
+
+/**
+ * Batch operation callback.
+ */
+function _simpletest_batch_operation($test_list_init, $test_id, &$context) {
+ simpletest_classloader_register();
+ // Get working values.
+ if (!isset($context['sandbox']['max'])) {
+ // First iteration: initialize working values.
+ $test_list = $test_list_init;
+ $context['sandbox']['max'] = count($test_list);
+ $test_results = array('#pass' => 0, '#fail' => 0, '#exception' => 0, '#debug' => 0);
+ }
+ else {
+ // Nth iteration: get the current values where we last stored them.
+ $test_list = $context['sandbox']['tests'];
+ $test_results = $context['sandbox']['test_results'];
+ }
+ $max = $context['sandbox']['max'];
+
+ // Perform the next test.
+ $test_class = array_shift($test_list);
+ $test = new $test_class($test_id);
+ $test->run();
+ $size = count($test_list);
+ $info = $test->getInfo();
+
+ module_invoke_all('test_finished', $test->results);
+
+ // Gather results and compose the report.
+ $test_results[$test_class] = $test->results;
+ foreach ($test_results[$test_class] as $key => $value) {
+ $test_results[$key] += $value;
+ }
+ $test_results[$test_class]['#name'] = $info['name'];
+ $items = array();
+ foreach (element_children($test_results) as $class) {
+ array_unshift($items, '<div class="simpletest-' . ($test_results[$class]['#fail'] + $test_results[$class]['#exception'] ? 'fail' : 'pass') . '">' . t('@name: @summary', array('@name' => $test_results[$class]['#name'], '@summary' => _simpletest_format_summary_line($test_results[$class]))) . '</div>');
+ }
+ $context['message'] = t('Processed test @num of @max - %test.', array('%test' => $info['name'], '@num' => $max - $size, '@max' => $max));
+ $context['message'] .= '<div class="simpletest-' . ($test_results['#fail'] + $test_results['#exception'] ? 'fail' : 'pass') . '">Overall results: ' . _simpletest_format_summary_line($test_results) . '</div>';
+ $context['message'] .= theme('item_list', array('items' => $items));
+
+ // Save working values for the next iteration.
+ $context['sandbox']['tests'] = $test_list;
+ $context['sandbox']['test_results'] = $test_results;
+ // The test_id is the only thing we need to save for the report page.
+ $context['results']['test_id'] = $test_id;
+
+ // Multistep processing: report progress.
+ $context['finished'] = 1 - $size / $max;
+}
+
+function _simpletest_batch_finished($success, $results, $operations, $elapsed) {
+ if ($success) {
+ drupal_set_message(t('The test run finished in @elapsed.', array('@elapsed' => $elapsed)));
+ }
+ else {
+ // Use the test_id passed as a parameter to _simpletest_batch_operation().
+ $test_id = $operations[0][1][1];
+
+ // Retrieve the last database prefix used for testing and the last test
+ // class that was run from. Use the information to read the lgo file
+ // in case any fatal errors caused the test to crash.
+ list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
+ simpletest_log_read($test_id, $last_prefix, $last_test_class);
+
+ drupal_set_message(t('The test run did not successfully finish.'), 'error');
+ drupal_set_message(t('Use the <em>Clean environment</em> button to clean-up temporary files and tables.'), 'warning');
+ }
+ module_invoke_all('test_group_finished');
+}
+
+/**
+ * Get information about the last test that ran given a test ID.
+ *
+ * @param $test_id
+ * The test ID to get the last test from.
+ * @return
+ * Array containing the last database prefix used and the last test class
+ * that ran.
+ */
+function simpletest_last_test_get($test_id) {
+ $last_prefix = db_query_range('SELECT last_prefix FROM {simpletest_test_id} WHERE test_id = :test_id', 0, 1, array(':test_id' => $test_id))->fetchField();
+ $last_test_class = db_query_range('SELECT test_class FROM {simpletest} WHERE test_id = :test_id ORDER BY message_id DESC', 0, 1, array(':test_id' => $test_id))->fetchField();
+ return array($last_prefix, $last_test_class);
+}
+
+/**
+ * Read the error log and report any errors as assertion failures.
+ *
+ * The errors in the log should only be fatal errors since any other errors
+ * will have been recorded by the error handler.
+ *
+ * @param $test_id
+ * The test ID to which the log relates.
+ * @param $prefix
+ * The database prefix to which the log relates.
+ * @param $test_class
+ * The test class to which the log relates.
+ * @param $during_test
+ * Indicates that the current file directory path is a temporary file
+ * file directory used during testing.
+ * @return
+ * Found any entries in log.
+ */
+function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALSE) {
+ $log = 'public://' . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/error.log';
+ $found = FALSE;
+ if (file_exists($log)) {
+ foreach (file($log) as $line) {
+ if (preg_match('/\[.*?\] (.*?): (.*?) in (.*) on line (\d+)/', $line, $match)) {
+ // Parse PHP fatal errors for example: PHP Fatal error: Call to
+ // undefined function break_me() in /path/to/file.php on line 17
+ $caller = array(
+ 'line' => $match[4],
+ 'file' => $match[3],
+ );
+ DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller);
+ }
+ else {
+ // Unknown format, place the entire message in the log.
+ DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error');
+ }
+ $found = TRUE;
+ }
+ }
+ return $found;
+}
+
+/**
+ * Get a list of all of the tests provided by the system.
+ *
+ * The list of test classes is loaded from the registry where it looks for
+ * files ending in ".test". Once loaded the test list is cached and stored in
+ * a static variable. In order to list tests provided by disabled modules
+ * hook_registry_files_alter() is used to forcefully add them to the registry.
+ *
+ * PSR-0 classes are found by searching the designated directory for each module
+ * for files matching the PSR-0 standard.
+ *
+ * @return
+ * An array of tests keyed with the groups specified in each of the tests
+ * getInfo() method and then keyed by the test class. An example of the array
+ * structure is provided below.
+ *
+ * @code
+ * $groups['Blog'] => array(
+ * 'BlogTestCase' => array(
+ * 'name' => 'Blog functionality',
+ * 'description' => 'Create, view, edit, delete, ...',
+ * 'group' => 'Blog',
+ * ),
+ * );
+ * @endcode
+ * @see simpletest_registry_files_alter()
+ */
+function simpletest_test_get_all() {
+ $groups = &drupal_static(__FUNCTION__);
+
+ if (!$groups) {
+ // Register a simple class loader for PSR-0 test classes.
+ simpletest_classloader_register();
+
+ // Load test information from cache if available, otherwise retrieve the
+ // information from each tests getInfo() method.
+ if ($cache = cache_get('simpletest', 'cache')) {
+ $groups = $cache->data;
+ }
+ else {
+ // Select all clases in files ending with .test.
+ $classes = db_query("SELECT name FROM {registry} WHERE type = :type AND filename LIKE :name", array(':type' => 'class', ':name' => '%.test'))->fetchCol();
+
+ // Also discover PSR-0 test classes, if the PHP version allows it.
+ if (version_compare(PHP_VERSION, '5.3') > 0) {
+
+ // Select all PSR-0 classes in the Tests namespace of all modules.
+ $system_list = db_query("SELECT name, filename FROM {system}")->fetchAllKeyed();
+
+ foreach ($system_list as $name => $filename) {
+ // Build directory in which the test files would reside.
+ $tests_dir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/Drupal/' . $name . '/Tests';
+ // Scan it for test files if it exists.
+ if (is_dir($tests_dir)) {
+ $files = file_scan_directory($tests_dir, '/.*\.php/');
+ if (!empty($files)) {
+ $basedir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/';
+ foreach ($files as $file) {
+ // Convert the file name into the namespaced class name.
+ $replacements = array(
+ '/' => '\\',
+ $basedir => '',
+ '.php' => '',
+ );
+ $classes[] = strtr($file->uri, $replacements);
+ }
+ }
+ }
+ }
+ }
+
+ // Check that each class has a getInfo() method and store the information
+ // in an array keyed with the group specified in the test information.
+ $groups = array();
+ foreach ($classes as $class) {
+ // Test classes need to implement getInfo() to be valid.
+ if (class_exists($class) && method_exists($class, 'getInfo')) {
+ $info = call_user_func(array($class, 'getInfo'));
+
+ // If this test class requires a non-existing module, skip it.
+ if (!empty($info['dependencies'])) {
+ foreach ($info['dependencies'] as $module) {
+ if (!drupal_get_filename('module', $module)) {
+ continue 2;
+ }
+ }
+ }
+
+ $groups[$info['group']][$class] = $info;
+ }
+ }
+
+ // Sort the groups and tests within the groups by name.
+ uksort($groups, 'strnatcasecmp');
+ foreach ($groups as $group => &$tests) {
+ uksort($tests, 'strnatcasecmp');
+ }
+
+ // Allow modules extending core tests to disable originals.
+ drupal_alter('simpletest', $groups);
+ cache_set('simpletest', $groups);
+ }
+ }
+ return $groups;
+}
+
+/*
+ * Register a simple class loader that can find D8-style PSR-0 test classes.
+ *
+ * Other PSR-0 class loading can happen in contrib, but those contrib class
+ * loader modules will not be enabled when testbot runs. So we need to do this
+ * one in core.
+ */
+function simpletest_classloader_register() {
+
+ // Prevent duplicate classloader registration.
+ static $first_run = TRUE;
+ if (!$first_run) {
+ return;
+ }
+ $first_run = FALSE;
+
+ // Only register PSR-0 class loading if we are on PHP 5.3 or higher.
+ if (version_compare(PHP_VERSION, '5.3') > 0) {
+ spl_autoload_register('_simpletest_autoload_psr0');
+ }
+}
+
+/**
+ * Autoload callback to find PSR-0 test classes.
+ *
+ * This will only work on classes where the namespace is of the pattern
+ * "Drupal\$extension\Tests\.."
+ */
+function _simpletest_autoload_psr0($class) {
+
+ // Static cache for extension paths.
+ // This cache is lazily filled as soon as it is needed.
+ static $extensions;
+
+ // Check that the first namespace fragment is "Drupal\"
+ if (substr($class, 0, 7) === 'Drupal\\') {
+ // Find the position of the second namespace separator.
+ $pos = strpos($class, '\\', 7);
+ // Check that the third namespace fragment is "\Tests\".
+ if (substr($class, $pos, 7) === '\\Tests\\') {
+
+ // Extract the second namespace fragment, which we expect to be the
+ // extension name.
+ $extension = substr($class, 7, $pos - 7);
+
+ // Lazy-load the extension paths, both enabled and disabled.
+ if (!isset($extensions)) {
+ $extensions = db_query("SELECT name, filename FROM {system}")->fetchAllKeyed();
+ }
+
+ // Check if the second namespace fragment is a known extension name.
+ if (isset($extensions[$extension])) {
+
+ // Split the class into namespace and classname.
+ $nspos = strrpos($class, '\\');
+ $namespace = substr($class, 0, $nspos);
+ $classname = substr($class, $nspos + 1);
+
+ // Build the filepath where we expect the class to be defined.
+ $path = dirname($extensions[$extension]) . '/lib/' .
+ str_replace('\\', '/', $namespace) . '/' .
+ str_replace('_', '/', $classname) . '.php';
+
+ // Include the file, if it does exist.
+ if (file_exists($path)) {
+ include $path;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_registry_files_alter().
+ *
+ * Add the test files for disabled modules so that we get a list containing
+ * all the avialable tests.
+ */
+function simpletest_registry_files_alter(&$files, $modules) {
+ foreach ($modules as $module) {
+ // Only add test files for disabled modules, as enabled modules should
+ // already include any test files they provide.
+ if (!$module->status) {
+ $dir = $module->dir;
+ if (!empty($module->info['files'])) {
+ foreach ($module->info['files'] as $file) {
+ if (substr($file, -5) == '.test') {
+ $files["$dir/$file"] = array('module' => $module->name, 'weight' => $module->weight);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Generate test file.
+ */
+function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') {
+ $size = $width * $lines - $lines;
+
+ // Generate random text
+ $text = '';
+ for ($i = 0; $i < $size; $i++) {
+ switch ($type) {
+ case 'text':
+ $text .= chr(rand(32, 126));
+ break;
+ case 'binary':
+ $text .= chr(rand(0, 31));
+ break;
+ case 'binary-text':
+ default:
+ $text .= rand(0, 1);
+ break;
+ }
+ }
+ $text = wordwrap($text, $width - 1, "\n", TRUE) . "\n"; // Add \n for symmetrical file.
+
+ // Create filename.
+ file_put_contents('public://' . $filename . '.txt', $text);
+ return $filename;
+}
+
+/**
+ * Remove all temporary database tables and directories.
+ */
+function simpletest_clean_environment() {
+ simpletest_clean_database();
+ simpletest_clean_temporary_directories();
+ if (variable_get('simpletest_clear_results', TRUE)) {
+ $count = simpletest_clean_results_table();
+ drupal_set_message(format_plural($count, 'Removed 1 test result.', 'Removed @count test results.'));
+ }
+ else {
+ drupal_set_message(t('Clear results is disabled and the test results table will not be cleared.'), 'warning');
+ }
+
+ // Detect test classes that have been added, renamed or deleted.
+ registry_rebuild();
+ cache_clear_all('simpletest', 'cache');
+}
+
+/**
+ * Removed prefixed tables from the database that are left over from crashed tests.
+ */
+function simpletest_clean_database() {
+ $tables = db_find_tables(Database::getConnection()->prefixTables('{simpletest}') . '%');
+ $schema = drupal_get_schema_unprocessed('simpletest');
+ $count = 0;
+ foreach (array_diff_key($tables, $schema) as $table) {
+ // Strip the prefix and skip tables without digits following "simpletest",
+ // e.g. {simpletest_test_id}.
+ if (preg_match('/simpletest\d+.*/', $table, $matches)) {
+ db_drop_table($matches[0]);
+ $count++;
+ }
+ }
+
+ if ($count > 0) {
+ drupal_set_message(format_plural($count, 'Removed 1 leftover table.', 'Removed @count leftover tables.'));
+ }
+ else {
+ drupal_set_message(t('No leftover tables to remove.'));
+ }
+}
+
+/**
+ * Find all leftover temporary directories and remove them.
+ */
+function simpletest_clean_temporary_directories() {
+ $count = 0;
+ if (is_dir('public://simpletest')) {
+ $files = scandir('public://simpletest');
+ foreach ($files as $file) {
+ $path = 'public://simpletest/' . $file;
+ if (is_dir($path) && is_numeric($file)) {
+ file_unmanaged_delete_recursive($path);
+ $count++;
+ }
+ }
+ }
+
+ if ($count > 0) {
+ drupal_set_message(format_plural($count, 'Removed 1 temporary directory.', 'Removed @count temporary directories.'));
+ }
+ else {
+ drupal_set_message(t('No temporary directories to remove.'));
+ }
+}
+
+/**
+ * Clear the test result tables.
+ *
+ * @param $test_id
+ * Test ID to remove results for, or NULL to remove all results.
+ * @return
+ * The number of results removed.
+ */
+function simpletest_clean_results_table($test_id = NULL) {
+ if (variable_get('simpletest_clear_results', TRUE)) {
+ if ($test_id) {
+ $count = db_query('SELECT COUNT(test_id) FROM {simpletest_test_id} WHERE test_id = :test_id', array(':test_id' => $test_id))->fetchField();
+
+ db_delete('simpletest')
+ ->condition('test_id', $test_id)
+ ->execute();
+ db_delete('simpletest_test_id')
+ ->condition('test_id', $test_id)
+ ->execute();
+ }
+ else {
+ $count = db_query('SELECT COUNT(test_id) FROM {simpletest_test_id}')->fetchField();
+
+ // Clear test results.
+ db_delete('simpletest')->execute();
+ db_delete('simpletest_test_id')->execute();
+ }
+
+ return $count;
+ }
+ return 0;
+}
+
+/**
+ * Implements hook_mail_alter().
+ *
+ * Aborts sending of messages with ID 'simpletest_cancel_test'.
+ *
+ * @see MailTestCase::testCancelMessage()
+ */
+function simpletest_mail_alter(&$message) {
+ if ($message['id'] == 'simpletest_cancel_test') {
+ $message['send'] = FALSE;
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.pages.inc b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.pages.inc
new file mode 100644
index 0000000..3127459
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.pages.inc
@@ -0,0 +1,513 @@
+<?php
+
+/**
+ * @file
+ * Page callbacks for simpletest module.
+ */
+
+/**
+ * List tests arranged in groups that can be selected and run.
+ */
+function simpletest_test_form($form) {
+ $form['tests'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Tests'),
+ '#description' => t('Select the test(s) or test group(s) you would like to run, and click <em>Run tests</em>.'),
+ );
+
+ $form['tests']['table'] = array(
+ '#theme' => 'simpletest_test_table',
+ );
+
+ // Generate the list of tests arranged by group.
+ $groups = simpletest_test_get_all();
+ foreach ($groups as $group => $tests) {
+ $form['tests']['table'][$group] = array(
+ '#collapsed' => TRUE,
+ );
+
+ foreach ($tests as $class => $info) {
+ $form['tests']['table'][$group][$class] = array(
+ '#type' => 'checkbox',
+ '#title' => $info['name'],
+ '#description' => $info['description'],
+ );
+ }
+ }
+
+ // Operation buttons.
+ $form['tests']['op'] = array(
+ '#type' => 'submit',
+ '#value' => t('Run tests'),
+ );
+ $form['clean'] = array(
+ '#type' => 'fieldset',
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ '#title' => t('Clean test environment'),
+ '#description' => t('Remove tables with the prefix "simpletest" and temporary directories that are left over from tests that crashed. This is intended for developers when creating tests.'),
+ );
+ $form['clean']['op'] = array(
+ '#type' => 'submit',
+ '#value' => t('Clean environment'),
+ '#submit' => array('simpletest_clean_environment'),
+ );
+
+ return $form;
+}
+
+/**
+ * Returns HTML for a test list generated by simpletest_test_form() into a table.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - table: A render element representing the table.
+ *
+ * @ingroup themeable
+ */
+function theme_simpletest_test_table($variables) {
+ $table = $variables['table'];
+
+ drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
+ drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js');
+ drupal_add_js('misc/tableselect.js');
+
+ // Create header for test selection table.
+ $header = array(
+ array('class' => array('select-all')),
+ array('data' => t('Test'), 'class' => array('simpletest_test')),
+ array('data' => t('Description'), 'class' => array('simpletest_description')),
+ );
+
+ // Define the images used to expand/collapse the test groups.
+ $js = array(
+ 'images' => array(
+ theme('image', array('path' => 'misc/menu-collapsed.png', 'width' => 7, 'height' => 7, 'alt' => t('Expand'), 'title' => t('Expand'))) . ' <a href="#" class="simpletest-collapse">(' . t('Expand') . ')</a>',
+ theme('image', array('path' => 'misc/menu-expanded.png', 'width' => 7, 'height' => 7, 'alt' => t('Collapse'), 'title' => t('Collapse'))) . ' <a href="#" class="simpletest-collapse">(' . t('Collapse') . ')</a>',
+ ),
+ );
+
+ // Cycle through each test group and create a row.
+ $rows = array();
+ foreach (element_children($table) as $key) {
+ $element = &$table[$key];
+ $row = array();
+
+ // Make the class name safe for output on the page by replacing all
+ // non-word/decimal characters with a dash (-).
+ $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-", $key)));
+
+ // Select the right "expand"/"collapse" image, depending on whether the
+ // category is expanded (at least one test selected) or not.
+ $collapsed = !empty($element['#collapsed']);
+ $image_index = $collapsed ? 0 : 1;
+
+ // Place-holder for checkboxes to select group of tests.
+ $row[] = array('id' => $test_class, 'class' => array('simpletest-select-all'));
+
+ // Expand/collapse image and group title.
+ $row[] = array(
+ 'data' => '<div class="simpletest-image" id="simpletest-test-group-' . $test_class . '"></div>' .
+ '<label for="' . $test_class . '-select-all" class="simpletest-group-label">' . $key . '</label>',
+ 'class' => array('simpletest-group-label'),
+ );
+
+ $row[] = array(
+ 'data' => '&nbsp;',
+ 'class' => array('simpletest-group-description'),
+ );
+
+ $rows[] = array('data' => $row, 'class' => array('simpletest-group'));
+
+ // Add individual tests to group.
+ $current_js = array(
+ 'testClass' => $test_class . '-test',
+ 'testNames' => array(),
+ 'imageDirection' => $image_index,
+ 'clickActive' => FALSE,
+ );
+
+ // Sorting $element by children's #title attribute instead of by class name.
+ uasort($element, 'element_sort_by_title');
+
+ // Cycle through each test within the current group.
+ foreach (element_children($element) as $test_name) {
+ $test = $element[$test_name];
+ $row = array();
+
+ $current_js['testNames'][] = $test['#id'];
+
+ // Store test title and description so that checkbox won't render them.
+ $title = $test['#title'];
+ $description = $test['#description'];
+
+ $test['#title_display'] = 'invisible';
+ unset($test['#description']);
+
+ // Test name is used to determine what tests to run.
+ $test['#name'] = $test_name;
+
+ $row[] = array(
+ 'data' => drupal_render($test),
+ 'class' => array('simpletest-test-select'),
+ );
+ $row[] = array(
+ 'data' => '<label for="' . $test['#id'] . '">' . $title . '</label>',
+ 'class' => array('simpletest-test-label'),
+ );
+ $row[] = array(
+ 'data' => '<div class="description">' . $description . '</div>',
+ 'class' => array('simpletest-test-description'),
+ );
+
+ $rows[] = array('data' => $row, 'class' => array($test_class . '-test', ($collapsed ? 'js-hide' : '')));
+ }
+ $js['simpletest-test-group-' . $test_class] = $current_js;
+ unset($table[$key]);
+ }
+
+ // Add js array of settings.
+ drupal_add_js(array('simpleTest' => $js), 'setting');
+
+ if (empty($rows)) {
+ return '<strong>' . t('No tests to display.') . '</strong>';
+ }
+ else {
+ return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'simpletest-form-table')));
+ }
+}
+
+/**
+ * Run selected tests.
+ */
+function simpletest_test_form_submit($form, &$form_state) {
+ simpletest_classloader_register();
+ // Get list of tests.
+ $tests_list = array();
+ foreach ($form_state['values'] as $class_name => $value) {
+ // Since class_exists() will likely trigger an autoload lookup,
+ // we do the fast check first.
+ if ($value === 1 && class_exists($class_name)) {
+ $tests_list[] = $class_name;
+ }
+ }
+ if (count($tests_list) > 0 ) {
+ $test_id = simpletest_run_tests($tests_list, 'drupal');
+ $form_state['redirect'] = 'admin/config/development/testing/results/' . $test_id;
+ }
+ else {
+ drupal_set_message(t('No test(s) selected.'), 'error');
+ }
+}
+
+/**
+ * Test results form for $test_id.
+ */
+function simpletest_result_form($form, &$form_state, $test_id) {
+ // Make sure there are test results to display and a re-run is not being performed.
+ $results = array();
+ if (is_numeric($test_id) && !$results = simpletest_result_get($test_id)) {
+ drupal_set_message(t('No test results to display.'), 'error');
+ drupal_goto('admin/config/development/testing');
+ return $form;
+ }
+
+ // Load all classes and include CSS.
+ drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
+
+ // Keep track of which test cases passed or failed.
+ $filter = array(
+ 'pass' => array(),
+ 'fail' => array(),
+ );
+
+ // Summary result fieldset.
+ $form['result'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Results'),
+ );
+ $form['result']['summary'] = $summary = array(
+ '#theme' => 'simpletest_result_summary',
+ '#pass' => 0,
+ '#fail' => 0,
+ '#exception' => 0,
+ '#debug' => 0,
+ );
+
+ simpletest_classloader_register();
+
+ // Cycle through each test group.
+ $header = array(t('Message'), t('Group'), t('Filename'), t('Line'), t('Function'), array('colspan' => 2, 'data' => t('Status')));
+ $form['result']['results'] = array();
+ foreach ($results as $group => $assertions) {
+ // Create group fieldset with summary information.
+ $info = call_user_func(array($group, 'getInfo'));
+ $form['result']['results'][$group] = array(
+ '#type' => 'fieldset',
+ '#title' => $info['name'],
+ '#description' => $info['description'],
+ '#collapsible' => TRUE,
+ );
+ $form['result']['results'][$group]['summary'] = $summary;
+ $group_summary = &$form['result']['results'][$group]['summary'];
+
+ // Create table of assertions for the group.
+ $rows = array();
+ foreach ($assertions as $assertion) {
+ $row = array();
+ $row[] = $assertion->message;
+ $row[] = $assertion->message_group;
+ $row[] = drupal_basename($assertion->file);
+ $row[] = $assertion->line;
+ $row[] = $assertion->function;
+ $row[] = simpletest_result_status_image($assertion->status);
+
+ $class = 'simpletest-' . $assertion->status;
+ if ($assertion->message_group == 'Debug') {
+ $class = 'simpletest-debug';
+ }
+ $rows[] = array('data' => $row, 'class' => array($class));
+
+ $group_summary['#' . $assertion->status]++;
+ $form['result']['summary']['#' . $assertion->status]++;
+ }
+ $form['result']['results'][$group]['table'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ );
+
+ // Set summary information.
+ $group_summary['#ok'] = $group_summary['#fail'] + $group_summary['#exception'] == 0;
+ $form['result']['results'][$group]['#collapsed'] = $group_summary['#ok'];
+
+ // Store test group (class) as for use in filter.
+ $filter[$group_summary['#ok'] ? 'pass' : 'fail'][] = $group;
+ }
+
+ // Overal summary status.
+ $form['result']['summary']['#ok'] = $form['result']['summary']['#fail'] + $form['result']['summary']['#exception'] == 0;
+
+ // Actions.
+ $form['#action'] = url('admin/config/development/testing/results/re-run');
+ $form['action'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Actions'),
+ '#attributes' => array('class' => array('container-inline')),
+ '#weight' => -11,
+ );
+
+ $form['action']['filter'] = array(
+ '#type' => 'select',
+ '#title' => 'Filter',
+ '#options' => array(
+ 'all' => t('All (@count)', array('@count' => count($filter['pass']) + count($filter['fail']))),
+ 'pass' => t('Pass (@count)', array('@count' => count($filter['pass']))),
+ 'fail' => t('Fail (@count)', array('@count' => count($filter['fail']))),
+ ),
+ );
+ $form['action']['filter']['#default_value'] = ($filter['fail'] ? 'fail' : 'all');
+
+ // Categorized test classes for to be used with selected filter value.
+ $form['action']['filter_pass'] = array(
+ '#type' => 'hidden',
+ '#default_value' => implode(',', $filter['pass']),
+ );
+ $form['action']['filter_fail'] = array(
+ '#type' => 'hidden',
+ '#default_value' => implode(',', $filter['fail']),
+ );
+
+ $form['action']['op'] = array(
+ '#type' => 'submit',
+ '#value' => t('Run tests'),
+ );
+
+ $form['action']['return'] = array(
+ '#type' => 'link',
+ '#title' => t('Return to list'),
+ '#href' => 'admin/config/development/testing',
+ );
+
+ if (is_numeric($test_id)) {
+ simpletest_clean_results_table($test_id);
+ }
+
+ return $form;
+}
+
+/**
+ * Re-run the tests that match the filter.
+ */
+function simpletest_result_form_submit($form, &$form_state) {
+ $pass = $form_state['values']['filter_pass'] ? explode(',', $form_state['values']['filter_pass']) : array();
+ $fail = $form_state['values']['filter_fail'] ? explode(',', $form_state['values']['filter_fail']) : array();
+
+ if ($form_state['values']['filter'] == 'all') {
+ $classes = array_merge($pass, $fail);
+ }
+ elseif ($form_state['values']['filter'] == 'pass') {
+ $classes = $pass;
+ }
+ else {
+ $classes = $fail;
+ }
+
+ if (!$classes) {
+ $form_state['redirect'] = 'admin/config/development/testing';
+ return;
+ }
+
+ $form_state_execute = array('values' => array());
+ foreach ($classes as $class) {
+ $form_state_execute['values'][$class] = 1;
+ }
+
+ simpletest_test_form_submit(array(), $form_state_execute);
+ $form_state['redirect'] = $form_state_execute['redirect'];
+}
+
+/**
+ * Returns HTML for the summary status of a simpletest result.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - form: A render element representing the form.
+ *
+ * @ingroup themeable
+ */
+function theme_simpletest_result_summary($variables) {
+ $form = $variables['form'];
+ return '<div class="simpletest-' . ($form['#ok'] ? 'pass' : 'fail') . '">' . _simpletest_format_summary_line($form) . '</div>';
+}
+
+/**
+ * Get test results for $test_id.
+ *
+ * @param $test_id The test_id to retrieve results of.
+ * @return Array of results grouped by test_class.
+ */
+function simpletest_result_get($test_id) {
+ $results = db_select('simpletest')
+ ->fields('simpletest')
+ ->condition('test_id', $test_id)
+ ->orderBy('test_class')
+ ->orderBy('message_id')
+ ->execute();
+
+ $test_results = array();
+ foreach ($results as $result) {
+ if (!isset($test_results[$result->test_class])) {
+ $test_results[$result->test_class] = array();
+ }
+ $test_results[$result->test_class][] = $result;
+ }
+ return $test_results;
+}
+
+/**
+ * Get the appropriate image for the status.
+ *
+ * @param $status Status string, either: pass, fail, exception.
+ * @return HTML image or false.
+ */
+function simpletest_result_status_image($status) {
+ // $map does not use drupal_static() as its value never changes.
+ static $map;
+
+ if (!isset($map)) {
+ $map = array(
+ 'pass' => theme('image', array('path' => 'misc/watchdog-ok.png', 'width' => 18, 'height' => 18, 'alt' => t('Pass'))),
+ 'fail' => theme('image', array('path' => 'misc/watchdog-error.png', 'width' => 18, 'height' => 18, 'alt' => t('Fail'))),
+ 'exception' => theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('Exception'))),
+ 'debug' => theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('Debug'))),
+ );
+ }
+ if (isset($map[$status])) {
+ return $map[$status];
+ }
+ return FALSE;
+}
+
+/**
+ * Provides settings form for SimpleTest variables.
+ *
+ * @ingroup forms
+ * @see simpletest_settings_form_validate()
+ */
+function simpletest_settings_form($form, &$form_state) {
+ $form['general'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('General'),
+ );
+ $form['general']['simpletest_clear_results'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Clear results after each complete test suite run'),
+ '#description' => t('By default SimpleTest will clear the results after they have been viewed on the results page, but in some cases it may be useful to leave the results in the database. The results can then be viewed at <em>admin/config/development/testing/[test_id]</em>. The test ID can be found in the database, simpletest table, or kept track of when viewing the results the first time. Additionally, some modules may provide more analysis or features that require this setting to be disabled.'),
+ '#default_value' => variable_get('simpletest_clear_results', TRUE),
+ );
+ $form['general']['simpletest_verbose'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Provide verbose information when running tests'),
+ '#description' => t('The verbose data will be printed along with the standard assertions and is useful for debugging. The verbose data will be erased between each test suite run. The verbose data output is very detailed and should only be used when debugging.'),
+ '#default_value' => variable_get('simpletest_verbose', TRUE),
+ );
+
+ $form['httpauth'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('HTTP authentication'),
+ '#description' => t('HTTP auth settings to be used by the SimpleTest browser during testing. Useful when the site requires basic HTTP authentication.'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['httpauth']['simpletest_httpauth_method'] = array(
+ '#type' => 'select',
+ '#title' => t('Method'),
+ '#options' => array(
+ CURLAUTH_BASIC => t('Basic'),
+ CURLAUTH_DIGEST => t('Digest'),
+ CURLAUTH_GSSNEGOTIATE => t('GSS negotiate'),
+ CURLAUTH_NTLM => t('NTLM'),
+ CURLAUTH_ANY => t('Any'),
+ CURLAUTH_ANYSAFE => t('Any safe'),
+ ),
+ '#default_value' => variable_get('simpletest_httpauth_method', CURLAUTH_BASIC),
+ );
+ $username = variable_get('simpletest_httpauth_username');
+ $password = variable_get('simpletest_httpauth_password');
+ $form['httpauth']['simpletest_httpauth_username'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Username'),
+ '#default_value' => $username,
+ );
+ if ($username && $password) {
+ $form['httpauth']['simpletest_httpauth_username']['#description'] = t('Leave this blank to delete both the existing username and password.');
+ }
+ $form['httpauth']['simpletest_httpauth_password'] = array(
+ '#type' => 'password',
+ '#title' => t('Password'),
+ );
+ if ($password) {
+ $form['httpauth']['simpletest_httpauth_password']['#description'] = t('To change the password, enter the new password here.');
+ }
+
+ return system_settings_form($form);
+}
+
+/**
+ * Validation handler for simpletest_settings_form().
+ */
+function simpletest_settings_form_validate($form, &$form_state) {
+ // If a username was provided but a password wasn't, preserve the existing
+ // password.
+ if (!empty($form_state['values']['simpletest_httpauth_username']) && empty($form_state['values']['simpletest_httpauth_password'])) {
+ $form_state['values']['simpletest_httpauth_password'] = variable_get('simpletest_httpauth_password', '');
+ }
+
+ // If a password was provided but a username wasn't, the credentials are
+ // incorrect, so throw an error.
+ if (empty($form_state['values']['simpletest_httpauth_username']) && !empty($form_state['values']['simpletest_httpauth_password'])) {
+ form_set_error('simpletest_httpauth_username', t('HTTP authentication credentials must include a username in addition to a password.'));
+ }
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.test b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.test
new file mode 100644
index 0000000..dde162e
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/simpletest.test
@@ -0,0 +1,746 @@
+<?php
+
+/**
+ * @file
+ * Tests for simpletest.module.
+ */
+
+class SimpleTestFunctionalTest extends DrupalWebTestCase {
+ /**
+ * The results array that has been parsed by getTestResults().
+ */
+ protected $childTestResults;
+
+ /**
+ * Store the test ID from each test run for comparison, to ensure they are
+ * incrementing.
+ */
+ protected $test_ids = array();
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'SimpleTest functionality',
+ 'description' => "Test SimpleTest's web interface: check that the intended tests were run and ensure that test reports display the intended results. Also test SimpleTest's internal browser and API's both explicitly and implicitly.",
+ 'group' => 'SimpleTest'
+ );
+ }
+
+ function setUp() {
+ if (!$this->inCURL()) {
+ parent::setUp('simpletest');
+
+ // Create and login user
+ $admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($admin_user);
+ }
+ else {
+ parent::setUp('non_existent_module');
+ }
+ }
+
+ /**
+ * Test the internal browsers functionality.
+ */
+ function testInternalBrowser() {
+ global $conf;
+ if (!$this->inCURL()) {
+ $this->drupalGet('node');
+ $this->assertTrue($this->drupalGetHeader('Date'), 'An HTTP header was received.');
+ $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.');
+ $this->assertNoTitle('Foo', 'Site title does not match.');
+ // Make sure that we are locked out of the installer when prefixing
+ // using the user-agent header. This is an important security check.
+ global $base_url;
+
+ $this->drupalGet($base_url . '/install.php', array('external' => TRUE));
+ $this->assertResponse(403, 'Cannot access install.php with a "simpletest" user-agent header.');
+
+ $user = $this->drupalCreateUser();
+ $this->drupalLogin($user);
+ $headers = $this->drupalGetHeaders(TRUE);
+ $this->assertEqual(count($headers), 2, 'There was one intermediate request.');
+ $this->assertTrue(strpos($headers[0][':status'], '302') !== FALSE, 'Intermediate response code was 302.');
+ $this->assertFalse(empty($headers[0]['location']), 'Intermediate request contained a Location header.');
+ $this->assertEqual($this->getUrl(), $headers[0]['location'], 'HTTP redirect was followed');
+ $this->assertFalse($this->drupalGetHeader('Location'), 'Headers from intermediate request were reset.');
+ $this->assertResponse(200, 'Response code from intermediate request was reset.');
+
+ // Test the maximum redirection option.
+ $this->drupalLogout();
+ $edit = array(
+ 'name' => $user->name,
+ 'pass' => $user->pass_raw
+ );
+ variable_set('simpletest_maximum_redirects', 1);
+ $this->drupalPost('user?destination=user/logout', $edit, t('Log in'));
+ $headers = $this->drupalGetHeaders(TRUE);
+ $this->assertEqual(count($headers), 2, 'Simpletest stopped following redirects after the first one.');
+ }
+ }
+
+ /**
+ * Test validation of the User-Agent header we use to perform test requests.
+ */
+ function testUserAgentValidation() {
+ if (!$this->inCURL()) {
+ global $base_url;
+ $simpletest_path = $base_url . '/' . drupal_get_path('module', 'simpletest');
+ $HTTP_path = $simpletest_path .'/tests/http.php?q=node';
+ $https_path = $simpletest_path .'/tests/https.php?q=node';
+ // Generate a valid simpletest User-Agent to pass validation.
+ $this->assertTrue(preg_match('/simpletest\d+/', $this->databasePrefix, $matches), 'Database prefix contains simpletest prefix.');
+ $test_ua = drupal_generate_test_ua($matches[0]);
+ $this->additionalCurlOptions = array(CURLOPT_USERAGENT => $test_ua);
+
+ // Test pages only available for testing.
+ $this->drupalGet($HTTP_path);
+ $this->assertResponse(200, 'Requesting http.php with a legitimate simpletest User-Agent returns OK.');
+ $this->drupalGet($https_path);
+ $this->assertResponse(200, 'Requesting https.php with a legitimate simpletest User-Agent returns OK.');
+
+ // Now slightly modify the HMAC on the header, which should not validate.
+ $this->additionalCurlOptions = array(CURLOPT_USERAGENT => $test_ua . 'X');
+ $this->drupalGet($HTTP_path);
+ $this->assertResponse(403, 'Requesting http.php with a bad simpletest User-Agent fails.');
+ $this->drupalGet($https_path);
+ $this->assertResponse(403, 'Requesting https.php with a bad simpletest User-Agent fails.');
+
+ // Use a real User-Agent and verify that the special files http.php and
+ // https.php can't be accessed.
+ $this->additionalCurlOptions = array(CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12');
+ $this->drupalGet($HTTP_path);
+ $this->assertResponse(403, 'Requesting http.php with a normal User-Agent fails.');
+ $this->drupalGet($https_path);
+ $this->assertResponse(403, 'Requesting https.php with a normal User-Agent fails.');
+ }
+ }
+
+ /**
+ * Make sure that tests selected through the web interface are run and
+ * that the results are displayed correctly.
+ */
+ function testWebTestRunner() {
+ $this->pass = t('SimpleTest pass.');
+ $this->fail = t('SimpleTest fail.');
+ $this->valid_permission = 'access content';
+ $this->invalid_permission = 'invalid permission';
+
+ if ($this->inCURL()) {
+ // Only run following code if this test is running itself through a CURL request.
+ $this->stubTest();
+ }
+ else {
+
+ // Run twice so test_ids can be accumulated.
+ for ($i = 0; $i < 2; $i++) {
+ // Run this test from web interface.
+ $this->drupalGet('admin/config/development/testing');
+
+ $edit = array();
+ $edit['SimpleTestFunctionalTest'] = TRUE;
+ $this->drupalPost(NULL, $edit, t('Run tests'));
+
+ // Parse results and confirm that they are correct.
+ $this->getTestResults();
+ $this->confirmStubTestResults();
+ }
+
+ // Regression test for #290316.
+ // Check that test_id is incrementing.
+ $this->assertTrue($this->test_ids[0] != $this->test_ids[1], 'Test ID is incrementing.');
+ }
+ }
+
+ /**
+ * Test to be run and the results confirmed.
+ */
+ function stubTest() {
+ $this->pass($this->pass);
+ $this->fail($this->fail);
+
+ $this->drupalCreateUser(array($this->valid_permission));
+ $this->drupalCreateUser(array($this->invalid_permission));
+
+ $this->pass(t('Test ID is @id.', array('@id' => $this->testId)));
+
+ // Generates a warning.
+ $i = 1 / 0;
+
+ // Call an assert function specific to that class.
+ $this->assertNothing();
+
+ // Generates a warning inside a PHP function.
+ array_key_exists(NULL, NULL);
+
+ debug('Foo', 'Debug');
+ }
+
+ /**
+ * Assert nothing.
+ */
+ function assertNothing() {
+ $this->pass("This is nothing.");
+ }
+
+ /**
+ * Confirm that the stub test produced the desired results.
+ */
+ function confirmStubTestResults() {
+ $this->assertAssertion(t('Enabled modules: %modules', array('%modules' => 'non_existent_module')), 'Other', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->setUp()');
+
+ $this->assertAssertion($this->pass, 'Other', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+ $this->assertAssertion($this->fail, 'Other', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ $this->assertAssertion(t('Created permissions: @perms', array('@perms' => $this->valid_permission)), 'Role', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+ $this->assertAssertion(t('Invalid permission %permission.', array('%permission' => $this->invalid_permission)), 'Role', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ // Check that a warning is caught by simpletest.
+ $this->assertAssertion('Division by zero', 'Warning', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ // Check that the backtracing code works for specific assert function.
+ $this->assertAssertion('This is nothing.', 'Other', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ // Check that errors that occur inside PHP internal functions are correctly reported.
+ // The exact error message differs between PHP versions so we check only
+ // the function name 'array_key_exists'.
+ $this->assertAssertion('array_key_exists', 'Warning', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ $this->assertAssertion("Debug: 'Foo'", 'Debug', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()');
+
+ $this->assertEqual('6 passes, 5 fails, 2 exceptions, and 1 debug message', $this->childTestResults['summary'], 'Stub test summary is correct');
+
+ $this->test_ids[] = $test_id = $this->getTestIdFromResults();
+ $this->assertTrue($test_id, 'Found test ID in results.');
+ }
+
+ /**
+ * Fetch the test id from the test results.
+ */
+ function getTestIdFromResults() {
+ foreach ($this->childTestResults['assertions'] as $assertion) {
+ if (preg_match('@^Test ID is ([0-9]*)\.$@', $assertion['message'], $matches)) {
+ return $matches[1];
+ }
+ }
+ return NULL;
+ }
+
+ /**
+ * Assert that an assertion with the specified values is displayed
+ * in the test results.
+ *
+ * @param string $message Assertion message.
+ * @param string $type Assertion type.
+ * @param string $status Assertion status.
+ * @param string $file File where the assertion originated.
+ * @param string $functuion Function where the assertion originated.
+ * @return Assertion result.
+ */
+ function assertAssertion($message, $type, $status, $file, $function) {
+ $message = trim(strip_tags($message));
+ $found = FALSE;
+ foreach ($this->childTestResults['assertions'] as $assertion) {
+ if ((strpos($assertion['message'], $message) !== FALSE) &&
+ $assertion['type'] == $type &&
+ $assertion['status'] == $status &&
+ $assertion['file'] == $file &&
+ $assertion['function'] == $function) {
+ $found = TRUE;
+ break;
+ }
+ }
+ return $this->assertTrue($found, format_string('Found assertion {"@message", "@type", "@status", "@file", "@function"}.', array('@message' => $message, '@type' => $type, '@status' => $status, "@file" => $file, "@function" => $function)));
+ }
+
+ /**
+ * Get the results from a test and store them in the class array $results.
+ */
+ function getTestResults() {
+ $results = array();
+ if ($this->parse()) {
+ if ($fieldset = $this->getResultFieldSet()) {
+ // Code assumes this is the only test in group.
+ $results['summary'] = $this->asText($fieldset->div->div[1]);
+ $results['name'] = $this->asText($fieldset->legend);
+
+ $results['assertions'] = array();
+ $tbody = $fieldset->div->table->tbody;
+ foreach ($tbody->tr as $row) {
+ $assertion = array();
+ $assertion['message'] = $this->asText($row->td[0]);
+ $assertion['type'] = $this->asText($row->td[1]);
+ $assertion['file'] = $this->asText($row->td[2]);
+ $assertion['line'] = $this->asText($row->td[3]);
+ $assertion['function'] = $this->asText($row->td[4]);
+ $ok_url = file_create_url('misc/watchdog-ok.png');
+ $assertion['status'] = ($row->td[5]->img['src'] == $ok_url) ? 'Pass' : 'Fail';
+ $results['assertions'][] = $assertion;
+ }
+ }
+ }
+ $this->childTestResults = $results;
+ }
+
+ /**
+ * Get the fieldset containing the results for group this test is in.
+ */
+ function getResultFieldSet() {
+ $fieldsets = $this->xpath('//fieldset');
+ $info = $this->getInfo();
+ foreach ($fieldsets as $fieldset) {
+ if ($this->asText($fieldset->legend) == $info['name']) {
+ return $fieldset;
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Extract the text contained by the element.
+ *
+ * @param $element
+ * Element to extract text from.
+ * @return
+ * Extracted text.
+ */
+ function asText(SimpleXMLElement $element) {
+ if (!is_object($element)) {
+ return $this->fail('The element is not an element.');
+ }
+ return trim(html_entity_decode(strip_tags($element->asXML())));
+ }
+
+ /**
+ * Check if the test is being run from inside a CURL request.
+ */
+ function inCURL() {
+ return (bool) drupal_valid_test_ua();
+ }
+}
+
+/**
+ * Test internal testing framework browser.
+ */
+class SimpleTestBrowserTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'SimpleTest browser',
+ 'description' => 'Test the internal browser of the testing framework.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+ variable_set('user_register', USER_REGISTER_VISITORS);
+ }
+
+ /**
+ * Test DrupalWebTestCase::getAbsoluteUrl().
+ */
+ function testGetAbsoluteUrl() {
+ // Testbed runs with Clean URLs disabled, so disable it here.
+ variable_set('clean_url', 0);
+ $url = 'user/login';
+
+ $this->drupalGet($url);
+ $absolute = url($url, array('absolute' => TRUE));
+ $this->assertEqual($absolute, $this->url, 'Passed and requested URL are equal.');
+ $this->assertEqual($this->url, $this->getAbsoluteUrl($this->url), 'Requested and returned absolute URL are equal.');
+
+ $this->drupalPost(NULL, array(), t('Log in'));
+ $this->assertEqual($absolute, $this->url, 'Passed and requested URL are equal.');
+ $this->assertEqual($this->url, $this->getAbsoluteUrl($this->url), 'Requested and returned absolute URL are equal.');
+
+ $this->clickLink('Create new account');
+ $url = 'user/register';
+ $absolute = url($url, array('absolute' => TRUE));
+ $this->assertEqual($absolute, $this->url, 'Passed and requested URL are equal.');
+ $this->assertEqual($this->url, $this->getAbsoluteUrl($this->url), 'Requested and returned absolute URL are equal.');
+ }
+
+ /**
+ * Tests XPath escaping.
+ */
+ function testXPathEscaping() {
+ $testpage = <<< EOF
+<html>
+<body>
+<a href="link1">A "weird" link, just to bother the dumb "XPath 1.0"</a>
+<a href="link2">A second "even more weird" link, in memory of George O'Malley</a>
+</body>
+</html>
+EOF;
+ $this->drupalSetContent($testpage);
+
+ // Matches the first link.
+ $urls = $this->xpath('//a[text()=:text]', array(':text' => 'A "weird" link, just to bother the dumb "XPath 1.0"'));
+ $this->assertEqual($urls[0]['href'], 'link1', 'Match with quotes.');
+
+ $urls = $this->xpath('//a[text()=:text]', array(':text' => 'A second "even more weird" link, in memory of George O\'Malley'));
+ $this->assertEqual($urls[0]['href'], 'link2', 'Match with mixed single and double quotes.');
+ }
+}
+
+class SimpleTestMailCaptureTestCase extends DrupalWebTestCase {
+ /**
+ * Implement getInfo().
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => 'SimpleTest e-mail capturing',
+ 'description' => 'Test the SimpleTest e-mail capturing logic, the assertMail assertion and the drupalGetMails function.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ /**
+ * Test to see if the wrapper function is executed correctly.
+ */
+ function testMailSend() {
+ // Create an e-mail.
+ $subject = $this->randomString(64);
+ $body = $this->randomString(128);
+ $message = array(
+ 'id' => 'drupal_mail_test',
+ 'headers' => array('Content-type'=> 'text/html'),
+ 'subject' => $subject,
+ 'to' => 'foobar@example.com',
+ 'body' => $body,
+ );
+
+ // Before we send the e-mail, drupalGetMails should return an empty array.
+ $captured_emails = $this->drupalGetMails();
+ $this->assertEqual(count($captured_emails), 0, 'The captured e-mails queue is empty.', 'E-mail');
+
+ // Send the e-mail.
+ $response = drupal_mail_system('simpletest', 'drupal_mail_test')->mail($message);
+
+ // Ensure that there is one e-mail in the captured e-mails array.
+ $captured_emails = $this->drupalGetMails();
+ $this->assertEqual(count($captured_emails), 1, 'One e-mail was captured.', 'E-mail');
+
+ // Assert that the e-mail was sent by iterating over the message properties
+ // and ensuring that they are captured intact.
+ foreach ($message as $field => $value) {
+ $this->assertMail($field, $value, format_string('The e-mail was sent and the value for property @field is intact.', array('@field' => $field)), 'E-mail');
+ }
+
+ // Send additional e-mails so more than one e-mail is captured.
+ for ($index = 0; $index < 5; $index++) {
+ $message = array(
+ 'id' => 'drupal_mail_test_' . $index,
+ 'headers' => array('Content-type'=> 'text/html'),
+ 'subject' => $this->randomString(64),
+ 'to' => $this->randomName(32) . '@example.com',
+ 'body' => $this->randomString(512),
+ );
+ drupal_mail_system('drupal_mail_test', $index)->mail($message);
+ }
+
+ // There should now be 6 e-mails captured.
+ $captured_emails = $this->drupalGetMails();
+ $this->assertEqual(count($captured_emails), 6, 'All e-mails were captured.', 'E-mail');
+
+ // Test different ways of getting filtered e-mails via drupalGetMails().
+ $captured_emails = $this->drupalGetMails(array('id' => 'drupal_mail_test'));
+ $this->assertEqual(count($captured_emails), 1, 'Only one e-mail is returned when filtering by id.', 'E-mail');
+ $captured_emails = $this->drupalGetMails(array('id' => 'drupal_mail_test', 'subject' => $subject));
+ $this->assertEqual(count($captured_emails), 1, 'Only one e-mail is returned when filtering by id and subject.', 'E-mail');
+ $captured_emails = $this->drupalGetMails(array('id' => 'drupal_mail_test', 'subject' => $subject, 'from' => 'this_was_not_used@example.com'));
+ $this->assertEqual(count($captured_emails), 0, 'No e-mails are returned when querying with an unused from address.', 'E-mail');
+
+ // Send the last e-mail again, so we can confirm that the drupalGetMails-filter
+ // correctly returns all e-mails with a given property/value.
+ drupal_mail_system('drupal_mail_test', $index)->mail($message);
+ $captured_emails = $this->drupalGetMails(array('id' => 'drupal_mail_test_4'));
+ $this->assertEqual(count($captured_emails), 2, 'All e-mails with the same id are returned when filtering by id.', 'E-mail');
+ }
+}
+
+/**
+ * Test Folder creation
+ */
+class SimpleTestFolderTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Testing SimpleTest setUp',
+ 'description' => "This test will check SimpleTest's treatment of hook_install during setUp. Image module is used for test.",
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ return parent::setUp('image');
+ }
+
+ function testFolderSetup() {
+ $directory = file_default_scheme() . '://styles';
+ $this->assertTrue(file_prepare_directory($directory, FALSE), 'Directory created.');
+ }
+}
+
+/**
+ * Test required modules for tests.
+ */
+class SimpleTestMissingDependentModuleUnitTest extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Testing dependent module test',
+ 'description' => 'This test should not load since it requires a module that is not found.',
+ 'group' => 'SimpleTest',
+ 'dependencies' => array('simpletest_missing_module'),
+ );
+ }
+
+ /**
+ * Ensure that this test will not be loaded despite its dependency.
+ */
+ function testFail() {
+ $this->fail(t('Running test with missing required module.'));
+ }
+}
+
+/**
+ * Tests a test case that does not run parent::setUp() in its setUp() method.
+ *
+ * If a test case does not call parent::setUp(), running
+ * DrupalTestCase::tearDown() would destroy the main site's database tables.
+ * Therefore, we ensure that tests which are not set up properly are skipped.
+ *
+ * @see DrupalTestCase
+ */
+class SimpleTestBrokenSetUp extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Broken SimpleTest method',
+ 'description' => 'Tests a test case that does not call parent::setUp().',
+ 'group' => 'SimpleTest'
+ );
+ }
+
+ function setUp() {
+ // If the test is being run from the main site, set up normally.
+ if (!drupal_valid_test_ua()) {
+ parent::setUp('simpletest');
+ // Create and log in user.
+ $admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($admin_user);
+ }
+ // If the test is being run from within simpletest, set up the broken test.
+ else {
+ $this->pass(t('The test setUp() method has been run.'));
+ // Don't call parent::setUp(). This should trigger an error message.
+ }
+ }
+
+ function tearDown() {
+ // If the test is being run from the main site, tear down normally.
+ if (!drupal_valid_test_ua()) {
+ parent::tearDown();
+ }
+ else {
+ // If the test is being run from within simpletest, output a message.
+ $this->pass(t('The tearDown() method has run.'));
+ }
+ }
+
+ /**
+ * Runs this test case from within the simpletest child site.
+ */
+ function testBreakSetUp() {
+ // If the test is being run from the main site, run it again from the web
+ // interface within the simpletest child site.
+ if (!drupal_valid_test_ua()) {
+ $edit['SimpleTestBrokenSetUp'] = TRUE;
+ $this->drupalPost('admin/config/development/testing', $edit, t('Run tests'));
+
+ // Verify that the broken test and its tearDown() method are skipped.
+ $this->assertRaw(t('The test setUp() method has been run.'));
+ $this->assertRaw(t('The test cannot be executed because it has not been set up properly.'));
+ $this->assertNoRaw(t('The test method has run.'));
+ $this->assertNoRaw(t('The tearDown() method has run.'));
+ }
+ // If the test is being run from within simpletest, output a message.
+ else {
+ $this->pass(t('The test method has run.'));
+ }
+ }
+}
+
+/**
+ * Verifies that tests bundled with installation profile modules are found.
+ */
+class SimpleTestInstallationProfileModuleTestsTestCase extends DrupalWebTestCase {
+ /**
+ * Use the Testing profile.
+ *
+ * The Testing profile contains drupal_system_listing_compatible_test.test,
+ * which attempts to:
+ * - run tests using the Minimal profile (which does not contain the
+ * drupal_system_listing_compatible_test.module)
+ * - but still install the drupal_system_listing_compatible_test.module
+ * contained in the Testing profile.
+ *
+ * @see DrupalSystemListingCompatibleTestCase
+ */
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Installation profile module tests',
+ 'description' => 'Verifies that tests bundled with installation profile modules are found.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('simpletest'));
+
+ $this->admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Tests existence of test case located in an installation profile module.
+ */
+ function testInstallationProfileTests() {
+ $this->drupalGet('admin/config/development/testing');
+ $this->assertText('Installation profile module tests helper');
+ $edit = array(
+ 'DrupalSystemListingCompatibleTestCase' => TRUE,
+ );
+ $this->drupalPost(NULL, $edit, t('Run tests'));
+ $this->assertText('DrupalSystemListingCompatibleTestCase test executed.');
+ }
+}
+
+/**
+ * Verifies that tests in other installation profiles are not found.
+ *
+ * @see SimpleTestInstallationProfileModuleTestsTestCase
+ */
+class SimpleTestOtherInstallationProfileModuleTestsTestCase extends DrupalWebTestCase {
+ /**
+ * Use the Minimal profile.
+ *
+ * The Testing profile contains drupal_system_listing_compatible_test.test,
+ * which should not be found.
+ *
+ * @see SimpleTestInstallationProfileModuleTestsTestCase
+ * @see DrupalSystemListingCompatibleTestCase
+ */
+ protected $profile = 'minimal';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Other Installation profiles',
+ 'description' => 'Verifies that tests in other installation profiles are not found.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('simpletest'));
+
+ $this->admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Tests that tests located in another installation profile do not appear.
+ */
+ function testOtherInstallationProfile() {
+ $this->drupalGet('admin/config/development/testing');
+ $this->assertNoText('Installation profile module tests helper');
+ }
+}
+
+/**
+ * Verifies that tests in other installation profiles are not found.
+ *
+ * @see SimpleTestInstallationProfileModuleTestsTestCase
+ */
+class SimpleTestDiscoveryTestCase extends DrupalWebTestCase {
+ /**
+ * Use the Testing profile.
+ *
+ * The Testing profile contains drupal_system_listing_compatible_test.test,
+ * which attempts to:
+ * - run tests using the Minimal profile (which does not contain the
+ * drupal_system_listing_compatible_test.module)
+ * - but still install the drupal_system_listing_compatible_test.module
+ * contained in the Testing profile.
+ *
+ * @see DrupalSystemListingCompatibleTestCase
+ */
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Discovery of test classes',
+ 'description' => 'Verifies that tests classes are discovered and can be autoloaded (class_exists).',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('simpletest'));
+
+ $this->admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Test discovery of PSR-0 test classes.
+ */
+ function testDiscoveryFunctions() {
+ if (version_compare(PHP_VERSION, '5.3') < 0) {
+ // Don't expect PSR-0 tests to be discovered on older PHP versions.
+ return;
+ }
+ // TODO: What if we have cached values? Do we need to force a cache refresh?
+ $classes_all = simpletest_test_get_all();
+ foreach (array(
+ 'Drupal\\simpletest\\Tests\\PSR0WebTest',
+ 'Drupal\\psr_0_test\\Tests\\ExampleTest',
+ ) as $class) {
+ $this->assert(!empty($classes_all['SimpleTest'][$class]), t('Class @class must be discovered by simpletest_test_get_all().', array('@class' => $class)));
+ }
+ }
+
+ /**
+ * Tests existence of test cases.
+ */
+ function testDiscovery() {
+ $this->drupalGet('admin/config/development/testing');
+ // Tests within enabled modules.
+ // (without these, this test wouldn't happen in the first place, so this is
+ // a bit pointless. We still run it for proof-of-concept.)
+ // This one is defined in system module.
+ $this->assertText('Drupal error handlers');
+ // This one is defined in simpletest module.
+ $this->assertText('Discovery of test classes');
+ // Tests within disabled modules.
+ if (version_compare(PHP_VERSION, '5.3') < 0) {
+ // Don't expect PSR-0 tests to be discovered on older PHP versions.
+ return;
+ }
+ // This one is provided by simpletest itself via PSR-0.
+ $this->assertText('PSR0 web test');
+ $this->assertText('PSR0 example test: PSR-0 in disabled modules.');
+ $this->assertText('PSR0 example test: PSR-0 in nested subfolders.');
+
+ // Test each test individually.
+ foreach (array(
+ 'Drupal\\psr_0_test\\Tests\\ExampleTest',
+ 'Drupal\\psr_0_test\\Tests\\Nested\\NestedExampleTest',
+ ) as $class) {
+ $this->drupalGet('admin/config/development/testing');
+ $edit = array($class => TRUE);
+ $this->drupalPost(NULL, $edit, t('Run tests'));
+ $this->assertText('The test run finished', t('Test @class must finish.', array('@class' => $class)));
+ $this->assertText('1 pass, 0 fails, and 0 exceptions', t('Test @class must pass.', array('@class' => $class)));
+ }
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions.test
new file mode 100644
index 0000000..4d58b59
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions.test
@@ -0,0 +1,126 @@
+<?php
+
+class ActionsConfigurationTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Actions configuration',
+ 'description' => 'Tests complex actions configuration by adding, editing, and deleting a complex action.',
+ 'group' => 'Actions',
+ );
+ }
+
+ /**
+ * Test the configuration of advanced actions through the administration
+ * interface.
+ */
+ function testActionConfiguration() {
+ // Create a user with permission to view the actions administration pages.
+ $user = $this->drupalCreateUser(array('administer actions'));
+ $this->drupalLogin($user);
+
+ // Make a POST request to admin/config/system/actions/manage.
+ $edit = array();
+ $edit['action'] = drupal_hash_base64('system_goto_action');
+ $this->drupalPost('admin/config/system/actions/manage', $edit, t('Create'));
+
+ // Make a POST request to the individual action configuration page.
+ $edit = array();
+ $action_label = $this->randomName();
+ $edit['actions_label'] = $action_label;
+ $edit['url'] = 'admin';
+ $this->drupalPost('admin/config/system/actions/configure/' . drupal_hash_base64('system_goto_action'), $edit, t('Save'));
+
+ // Make sure that the new complex action was saved properly.
+ $this->assertText(t('The action has been successfully saved.'), t("Make sure we get a confirmation that we've successfully saved the complex action."));
+ $this->assertText($action_label, t("Make sure the action label appears on the configuration page after we've saved the complex action."));
+
+ // Make another POST request to the action edit page.
+ $this->clickLink(t('configure'));
+ preg_match('|admin/config/system/actions/configure/(\d+)|', $this->getUrl(), $matches);
+ $aid = $matches[1];
+ $edit = array();
+ $new_action_label = $this->randomName();
+ $edit['actions_label'] = $new_action_label;
+ $edit['url'] = 'admin';
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ // Make sure that the action updated properly.
+ $this->assertText(t('The action has been successfully saved.'), t("Make sure we get a confirmation that we've successfully updated the complex action."));
+ $this->assertNoText($action_label, t("Make sure the old action label does NOT appear on the configuration page after we've updated the complex action."));
+ $this->assertText($new_action_label, t("Make sure the action label appears on the configuration page after we've updated the complex action."));
+
+ // Make sure that deletions work properly.
+ $this->clickLink(t('delete'));
+ $edit = array();
+ $this->drupalPost("admin/config/system/actions/delete/$aid", $edit, t('Delete'));
+
+ // Make sure that the action was actually deleted.
+ $this->assertRaw(t('Action %action was deleted', array('%action' => $new_action_label)), t('Make sure that we get a delete confirmation message.'));
+ $this->drupalGet('admin/config/system/actions/manage');
+ $this->assertNoText($new_action_label, t("Make sure the action label does not appear on the overview page after we've deleted the action."));
+ $exists = db_query('SELECT aid FROM {actions} WHERE callback = :callback', array(':callback' => 'drupal_goto_action'))->fetchField();
+ $this->assertFalse($exists, t('Make sure the action is gone from the database after being deleted.'));
+ }
+}
+
+/**
+ * Test actions executing in a potential loop, and make sure they abort properly.
+ */
+class ActionLoopTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Actions executing in a potentially infinite loop',
+ 'description' => 'Tests actions executing in a loop, and makes sure they abort properly.',
+ 'group' => 'Actions',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('dblog', 'trigger', 'actions_loop_test');
+ }
+
+ /**
+ * Set up a loop with 3 - 12 recursions, and see if it aborts properly.
+ */
+ function testActionLoop() {
+ $user = $this->drupalCreateUser(array('administer actions'));
+ $this->drupalLogin($user);
+
+ $hash = drupal_hash_base64('actions_loop_test_log');
+ $edit = array('aid' => $hash);
+ $this->drupalPost('admin/structure/trigger/actions_loop_test', $edit, t('Assign'));
+
+ // Delete any existing watchdog messages to clear the plethora of
+ // "Action added" messages from when Drupal was installed.
+ db_delete('watchdog')->execute();
+ // To prevent this test from failing when xdebug is enabled, the maximum
+ // recursion level should be kept low enough to prevent the xdebug
+ // infinite recursion protection mechanism from aborting the request.
+ // See http://drupal.org/node/587634.
+ variable_set('actions_max_stack', 7);
+ $this->triggerActions();
+ }
+
+ /**
+ * Create an infinite loop by causing a watchdog message to be set,
+ * which causes the actions to be triggered again, up to actions_max_stack
+ * times.
+ */
+ protected function triggerActions() {
+ $this->drupalGet('<front>', array('query' => array('trigger_actions_on_watchdog' => TRUE)));
+ $expected = array();
+ $expected[] = 'Triggering action loop';
+ for ($i = 1; $i <= variable_get('actions_max_stack', 35); $i++) {
+ $expected[] = "Test log #$i";
+ }
+ $expected[] = 'Stack overflow: too many calls to actions_do(). Aborting to prevent infinite recursion.';
+
+ $result = db_query("SELECT message FROM {watchdog} WHERE type = 'actions_loop_test' OR type = 'actions' ORDER BY wid");
+ $loop_started = FALSE;
+ foreach ($result as $row) {
+ $expected_message = array_shift($expected);
+ $this->assertEqual($row->message, $expected_message, t('Expected message %expected, got %message.', array('%expected' => $expected_message, '%message' => $row->message)));
+ }
+ $this->assertTrue(empty($expected), t('All expected messages found.'));
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.info b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.info
new file mode 100644
index 0000000..dfd6d67
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.info
@@ -0,0 +1,12 @@
+name = Actions loop test
+description = Support module for action loop testing.
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.install b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.install
new file mode 100644
index 0000000..b22fd85
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.install
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Implements hook_install().
+ */
+function actions_loop_test_install() {
+ db_update('system')
+ ->fields(array('weight' => 1))
+ ->condition('name', 'actions_loop_test')
+ ->execute();
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.module b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.module
new file mode 100644
index 0000000..261cb80
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/actions_loop_test.module
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * Implements hook_trigger_info().
+ */
+function actions_loop_test_trigger_info() {
+ return array(
+ 'actions_loop_test' => array(
+ 'watchdog' => array(
+ 'label' => t('When a message is logged'),
+ ),
+ ),
+ );
+}
+
+/**
+ * Implements hook_watchdog().
+ */
+function actions_loop_test_watchdog(array $log_entry) {
+ // If the triggering actions are not explicitly enabled, abort.
+ if (empty($_GET['trigger_actions_on_watchdog'])) {
+ return;
+ }
+ // Get all the action ids assigned to the trigger on the watchdog hook's
+ // "run" event.
+ $aids = trigger_get_assigned_actions('watchdog');
+ // We can pass in any applicable information in $context. There isn't much in
+ // this case, but we'll pass in the hook name as the bare minimum.
+ $context = array(
+ 'hook' => 'watchdog',
+ );
+ // Fire the actions on the associated object ($log_entry) and the context
+ // variable.
+ actions_do(array_keys($aids), $log_entry, $context);
+}
+
+/**
+ * Implements hook_init().
+ */
+function actions_loop_test_init() {
+ if (!empty($_GET['trigger_actions_on_watchdog'])) {
+ watchdog_skip_semaphore('actions_loop_test', 'Triggering action loop');
+ }
+}
+
+/**
+ * Implements hook_action_info().
+ */
+function actions_loop_test_action_info() {
+ return array(
+ 'actions_loop_test_log' => array(
+ 'label' => t('Write a message to the log.'),
+ 'type' => 'system',
+ 'configurable' => FALSE,
+ 'triggers' => array('any'),
+ ),
+ );
+}
+
+/**
+ * Write a message to the log.
+ */
+function actions_loop_test_log() {
+ $count = &drupal_static(__FUNCTION__, 0);
+ $count++;
+ watchdog_skip_semaphore('actions_loop_test', "Test log #$count");
+}
+
+/**
+ * Replacement of the watchdog() function that eliminates the use of semaphores
+ * so that we can test the abortion of an action loop.
+ */
+function watchdog_skip_semaphore($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
+ global $user, $base_root;
+
+ // Prepare the fields to be logged
+ $log_entry = array(
+ 'type' => $type,
+ 'message' => $message,
+ 'variables' => $variables,
+ 'severity' => $severity,
+ 'link' => $link,
+ 'user' => $user,
+ 'uid' => isset($user->uid) ? $user->uid : 0,
+ 'request_uri' => $base_root . request_uri(),
+ 'referer' => $_SERVER['HTTP_REFERER'],
+ 'ip' => ip_address(),
+ 'timestamp' => REQUEST_TIME,
+ );
+
+ // Call the logging hooks to log/process the message
+ foreach (module_implements('watchdog') as $module) {
+ module_invoke($module, 'watchdog', $log_entry);
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax.test
new file mode 100644
index 0000000..664d520
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax.test
@@ -0,0 +1,530 @@
+<?php
+
+class AJAXTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ parent::setUp(array_unique(array_merge(array('ajax_test', 'ajax_forms_test'), $modules)));
+ }
+
+ /**
+ * Assert that a command with the required properties exists within the array of Ajax commands returned by the server.
+ *
+ * The Ajax framework, via the ajax_deliver() and ajax_render() functions,
+ * returns an array of commands. This array sometimes includes commands
+ * automatically provided by the framework in addition to commands returned by
+ * a particular page callback. During testing, we're usually interested that a
+ * particular command is present, and don't care whether other commands
+ * precede or follow the one we're interested in. Additionally, the command
+ * we're interested in may include additional data that we're not interested
+ * in. Therefore, this function simply asserts that one of the commands in
+ * $haystack contains all of the keys and values in $needle. Furthermore, if
+ * $needle contains a 'settings' key with an array value, we simply assert
+ * that all keys and values within that array are present in the command we're
+ * checking, and do not consider it a failure if the actual command contains
+ * additional settings that aren't part of $needle.
+ *
+ * @param $haystack
+ * An array of Ajax commands returned by the server.
+ * @param $needle
+ * Array of info we're expecting in one of those commands.
+ * @param $message
+ * An assertion message.
+ */
+ protected function assertCommand($haystack, $needle, $message) {
+ $found = FALSE;
+ foreach ($haystack as $command) {
+ // If the command has additional settings that we're not testing for, do
+ // not consider that a failure.
+ if (isset($command['settings']) && is_array($command['settings']) && isset($needle['settings']) && is_array($needle['settings'])) {
+ $command['settings'] = array_intersect_key($command['settings'], $needle['settings']);
+ }
+ // If the command has additional data that we're not testing for, do not
+ // consider that a failure. Also, == instead of ===, because we don't
+ // require the key/value pairs to be in any particular order
+ // (http://www.php.net/manual/en/language.operators.array.php).
+ if (array_intersect_key($command, $needle) == $needle) {
+ $found = TRUE;
+ break;
+ }
+ }
+ $this->assertTrue($found, $message);
+ }
+}
+
+/**
+ * Tests primary Ajax framework functions.
+ */
+class AJAXFrameworkTestCase extends AJAXTestCase {
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'AJAX framework',
+ 'description' => 'Performs tests on AJAX framework functions.',
+ 'group' => 'AJAX',
+ );
+ }
+
+ /**
+ * Test that ajax_render() returns JavaScript settings generated during the page request.
+ *
+ * @todo Add tests to ensure that ajax_render() returns commands for new CSS
+ * and JavaScript files to be loaded by the page. See
+ * http://drupal.org/node/561858.
+ */
+ function testAJAXRender() {
+ $commands = $this->drupalGetAJAX('ajax-test/render');
+
+ // Verify that there is a command to load settings added with
+ // drupal_add_js().
+ $expected = array(
+ 'command' => 'settings',
+ 'settings' => array('basePath' => base_path(), 'ajax' => 'test'),
+ );
+ $this->assertCommand($commands, $expected, t('ajax_render() loads settings added with drupal_add_js().'));
+
+ // Verify that Ajax settings are loaded for #type 'link'.
+ $this->drupalGet('ajax-test/link');
+ $settings = $this->drupalGetSettings();
+ $this->assertEqual($settings['ajax']['ajax-link']['url'], url('filter/tips'));
+ $this->assertEqual($settings['ajax']['ajax-link']['wrapper'], 'block-system-main');
+ }
+
+ /**
+ * Test behavior of ajax_render_error().
+ */
+ function testAJAXRenderError() {
+ // Verify default error message.
+ $commands = $this->drupalGetAJAX('ajax-test/render-error');
+ $expected = array(
+ 'command' => 'alert',
+ 'text' => t('An error occurred while handling the request: The server received invalid input.'),
+ );
+ $this->assertCommand($commands, $expected, t('ajax_render_error() invokes alert command.'));
+
+ // Verify custom error message.
+ $edit = array(
+ 'message' => 'Custom error message.',
+ );
+ $commands = $this->drupalGetAJAX('ajax-test/render-error', array('query' => $edit));
+ $expected = array(
+ 'command' => 'alert',
+ 'text' => $edit['message'],
+ );
+ $this->assertCommand($commands, $expected, t('Custom error message is output.'));
+ }
+
+ /**
+ * Test that new JavaScript and CSS files added during an AJAX request are returned.
+ */
+ function testLazyLoad() {
+ $expected = array(
+ 'setting_name' => 'ajax_forms_test_lazy_load_form_submit',
+ 'setting_value' => 'executed',
+ 'css' => drupal_get_path('module', 'system') . '/system.admin.css',
+ 'js' => drupal_get_path('module', 'system') . '/system.js',
+ );
+ // @todo D8: Add a drupal_css_defaults() helper function.
+ $expected_css_html = drupal_get_css(array($expected['css'] => array(
+ 'type' => 'file',
+ 'group' => CSS_DEFAULT,
+ 'weight' => 0,
+ 'every_page' => FALSE,
+ 'media' => 'all',
+ 'preprocess' => TRUE,
+ 'data' => $expected['css'],
+ 'browsers' => array('IE' => TRUE, '!IE' => TRUE),
+ )), TRUE);
+ $expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
+
+ // Get the base page.
+ $this->drupalGet('ajax_forms_test_lazy_load_form');
+ $original_settings = $this->drupalGetSettings();
+ $original_css = $original_settings['ajaxPageState']['css'];
+ $original_js = $original_settings['ajaxPageState']['js'];
+
+ // Verify that the base page doesn't have the settings and files that are to
+ // be lazy loaded as part of the next requests.
+ $this->assertTrue(!isset($original_settings[$expected['setting_name']]), t('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
+ $this->assertTrue(!isset($original_settings[$expected['css']]), t('Page originally lacks the %css file, as expected.', array('%css' => $expected['css'])));
+ $this->assertTrue(!isset($original_settings[$expected['js']]), t('Page originally lacks the %js file, as expected.', array('%js' => $expected['js'])));
+
+ // Submit the AJAX request without triggering files getting added.
+ $commands = $this->drupalPostAJAX(NULL, array('add_files' => FALSE), array('op' => t('Submit')));
+ $new_settings = $this->drupalGetSettings();
+
+ // Verify the setting was not added when not expected.
+ $this->assertTrue(!isset($new_settings['setting_name']), t('Page still lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
+ // Verify a settings command does not add CSS or scripts to Drupal.settings
+ // and no command inserts the corresponding tags on the page.
+ $found_settings_command = FALSE;
+ $found_markup_command = FALSE;
+ foreach ($commands as $command) {
+ if ($command['command'] == 'settings' && (array_key_exists('css', $command['settings']['ajaxPageState']) || array_key_exists('js', $command['settings']['ajaxPageState']))) {
+ $found_settings_command = TRUE;
+ }
+ if (isset($command['data']) && ($command['data'] == $expected_js_html || $command['data'] == $expected_css_html)) {
+ $found_markup_command = TRUE;
+ }
+ }
+ $this->assertFalse($found_settings_command, t('Page state still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
+ $this->assertFalse($found_markup_command, t('Page still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
+
+ // Submit the AJAX request and trigger adding files.
+ $commands = $this->drupalPostAJAX(NULL, array('add_files' => TRUE), array('op' => t('Submit')));
+ $new_settings = $this->drupalGetSettings();
+ $new_css = $new_settings['ajaxPageState']['css'];
+ $new_js = $new_settings['ajaxPageState']['js'];
+
+ // Verify the expected setting was added.
+ $this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], t('Page now has the %setting.', array('%setting' => $expected['setting_name'])));
+
+ // Verify the expected CSS file was added, both to Drupal.settings, and as
+ // an AJAX command for inclusion into the HTML.
+ $this->assertEqual($new_css, $original_css + array($expected['css'] => 1), t('Page state now has the %css file.', array('%css' => $expected['css'])));
+ $this->assertCommand($commands, array('data' => $expected_css_html), t('Page now has the %css file.', array('%css' => $expected['css'])));
+
+ // Verify the expected JS file was added, both to Drupal.settings, and as
+ // an AJAX command for inclusion into the HTML. By testing for an exact HTML
+ // string containing the SCRIPT tag, we also ensure that unexpected
+ // JavaScript code, such as a jQuery.extend() that would potentially clobber
+ // rather than properly merge settings, didn't accidentally get added.
+ $this->assertEqual($new_js, $original_js + array($expected['js'] => 1), t('Page state now has the %js file.', array('%js' => $expected['js'])));
+ $this->assertCommand($commands, array('data' => $expected_js_html), t('Page now has the %js file.', array('%js' => $expected['js'])));
+ }
+
+ /**
+ * Tests that overridden CSS files are not added during lazy load.
+ */
+ function testLazyLoadOverriddenCSS() {
+ // The test theme overrides system.base.css without an implementation,
+ // thereby removing it.
+ theme_enable(array('test_theme'));
+ variable_set('theme_default', 'test_theme');
+
+ // This gets the form, and emulates an Ajax submission on it, including
+ // adding markup to the HEAD and BODY for any lazy loaded JS/CSS files.
+ $this->drupalPostAJAX('ajax_forms_test_lazy_load_form', array('add_files' => TRUE), array('op' => t('Submit')));
+
+ // Verify that the resulting HTML does not load the overridden CSS file.
+ // We add a "?" to the assertion, because Drupal.settings may include
+ // information about the file; we only really care about whether it appears
+ // in a LINK or STYLE tag, for which Drupal always adds a query string for
+ // cache control.
+ $this->assertNoText('system.base.css?', 'Ajax lazy loading does not add overridden CSS files.');
+ }
+}
+
+/**
+ * Tests Ajax framework commands.
+ */
+class AJAXCommandsTestCase extends AJAXTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'AJAX commands',
+ 'description' => 'Performs tests on AJAX framework commands.',
+ 'group' => 'AJAX',
+ );
+ }
+
+ /**
+ * Test the various Ajax Commands.
+ */
+ function testAJAXCommands() {
+ $form_path = 'ajax_forms_test_ajax_commands_form';
+ $web_user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($web_user);
+
+ $edit = array();
+
+ // Tests the 'after' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'After': Click to put something after the div")));
+ $expected = array(
+ 'command' => 'insert',
+ 'method' => 'after',
+ 'data' => 'This will be placed after',
+ );
+ $this->assertCommand($commands, $expected, "'after' AJAX command issued with correct data");
+
+ // Tests the 'alert' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Alert': Click to alert")));
+ $expected = array(
+ 'command' => 'alert',
+ 'text' => 'Alert',
+ );
+ $this->assertCommand($commands, $expected, "'alert' AJAX Command issued with correct text");
+
+ // Tests the 'append' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Append': Click to append something")));
+ $expected = array(
+ 'command' => 'insert',
+ 'method' => 'append',
+ 'data' => 'Appended text',
+ );
+ $this->assertCommand($commands, $expected, "'append' AJAX command issued with correct data");
+
+ // Tests the 'before' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'before': Click to put something before the div")));
+ $expected = array(
+ 'command' => 'insert',
+ 'method' => 'before',
+ 'data' => 'Before text',
+ );
+ $this->assertCommand($commands, $expected, "'before' AJAX command issued with correct data");
+
+ // Tests the 'changed' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed.")));
+ $expected = array(
+ 'command' => 'changed',
+ 'selector' => '#changed_div',
+ );
+ $this->assertCommand($commands, $expected, "'changed' AJAX command issued with correct selector");
+
+ // Tests the 'changed' command using the second argument.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed with asterisk.")));
+ $expected = array(
+ 'command' => 'changed',
+ 'selector' => '#changed_div',
+ 'asterisk' => '#changed_div_mark_this',
+ );
+ $this->assertCommand($commands, $expected, "'changed' AJAX command (with asterisk) issued with correct selector");
+
+ // Tests the 'css' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("Set the the '#box' div to be blue.")));
+ $expected = array(
+ 'command' => 'css',
+ 'selector' => '#css_div',
+ 'argument' => array('background-color' => 'blue'),
+ );
+ $this->assertCommand($commands, $expected, "'css' AJAX command issued with correct selector");
+
+ // Tests the 'data' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX data command: Issue command.")));
+ $expected = array(
+ 'command' => 'data',
+ 'name' => 'testkey',
+ 'value' => 'testvalue',
+ );
+ $this->assertCommand($commands, $expected, "'data' AJAX command issued with correct key and value");
+
+ // Tests the 'invoke' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX invoke command: Invoke addClass() method.")));
+ $expected = array(
+ 'command' => 'invoke',
+ 'method' => 'addClass',
+ 'arguments' => array('error'),
+ );
+ $this->assertCommand($commands, $expected, "'invoke' AJAX command issued with correct method and argument");
+
+ // Tests the 'html' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX html: Replace the HTML in a selector.")));
+ $expected = array(
+ 'command' => 'insert',
+ 'method' => 'html',
+ 'data' => 'replacement text',
+ );
+ $this->assertCommand($commands, $expected, "'html' AJAX command issued with correct data");
+
+ // Tests the 'insert' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX insert: Let client insert based on #ajax['method'].")));
+ $expected = array(
+ 'command' => 'insert',
+ 'data' => 'insert replacement text',
+ );
+ $this->assertCommand($commands, $expected, "'insert' AJAX command issued with correct data");
+
+ // Tests the 'prepend' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'prepend': Click to prepend something")));
+ $expected = array(
+ 'command' => 'insert',
+ 'method' => 'prepend',
+ 'data' => 'prepended text',
+ );
+ $this->assertCommand($commands, $expected, "'prepend' AJAX command issued with correct data");
+
+ // Tests the 'remove' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'remove': Click to remove text")));
+ $expected = array(
+ 'command' => 'remove',
+ 'selector' => '#remove_text',
+ );
+ $this->assertCommand($commands, $expected, "'remove' AJAX command issued with correct command and selector");
+
+ // Tests the 'restripe' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'restripe' command")));
+ $expected = array(
+ 'command' => 'restripe',
+ 'selector' => '#restripe_table',
+ );
+ $this->assertCommand($commands, $expected, "'restripe' AJAX command issued with correct selector");
+
+ // Tests the 'settings' command.
+ $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'settings' command")));
+ $expected = array(
+ 'command' => 'settings',
+ 'settings' => array('ajax_forms_test' => array('foo' => 42)),
+ );
+ $this->assertCommand($commands, $expected, "'settings' AJAX command issued with correct data");
+ }
+}
+
+/**
+ * Test that $form_state['values'] is properly delivered to $ajax['callback'].
+ */
+class AJAXFormValuesTestCase extends AJAXTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'AJAX command form values',
+ 'description' => 'Tests that form values are properly delivered to AJAX callbacks.',
+ 'group' => 'AJAX',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+
+ $this->web_user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($this->web_user);
+ }
+
+ /**
+ * Create a simple form, then POST to system/ajax to change to it.
+ */
+ function testSimpleAJAXFormValue() {
+ // Verify form values of a select element.
+ foreach (array('red', 'green', 'blue') as $item) {
+ $edit = array(
+ 'select' => $item,
+ );
+ $commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'select');
+ $expected = array(
+ 'command' => 'data',
+ 'value' => $item,
+ );
+ $this->assertCommand($commands, $expected, "verification of AJAX form values from a selectbox issued with a correct value");
+ }
+
+ // Verify form values of a checkbox element.
+ foreach (array(FALSE, TRUE) as $item) {
+ $edit = array(
+ 'checkbox' => $item,
+ );
+ $commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'checkbox');
+ $expected = array(
+ 'command' => 'data',
+ 'value' => (int) $item,
+ );
+ $this->assertCommand($commands, $expected, "verification of AJAX form values from a checkbox issued with a correct value");
+ }
+ }
+}
+
+/**
+ * Tests that Ajax-enabled forms work when multiple instances of the same form are on a page.
+ */
+class AJAXMultiFormTestCase extends AJAXTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'AJAX multi form',
+ 'description' => 'Tests that AJAX-enabled forms work when multiple instances of the same form are on a page.',
+ 'group' => 'AJAX',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('form_test'));
+
+ // Create a multi-valued field for 'page' nodes to use for Ajax testing.
+ $field_name = 'field_ajax_test';
+ $field = array(
+ 'field_name' => $field_name,
+ 'type' => 'text',
+ 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+ );
+ field_create_field($field);
+ $instance = array(
+ 'field_name' => $field_name,
+ 'entity_type' => 'node',
+ 'bundle' => 'page',
+ );
+ field_create_instance($instance);
+
+ // Login a user who can create 'page' nodes.
+ $this->web_user = $this->drupalCreateUser(array('create page content'));
+ $this->drupalLogin($this->web_user);
+ }
+
+ /**
+ * Test that a page with the 'page_node_form' included twice works correctly.
+ */
+ function testMultiForm() {
+ // HTML IDs for elements within the field are potentially modified with
+ // each Ajax submission, but these variables are stable and help target the
+ // desired elements.
+ $field_name = 'field_ajax_test';
+ $field_xpaths = array(
+ 'page-node-form' => '//form[@id="page-node-form"]//div[contains(@class, "field-name-field-ajax-test")]',
+ 'page-node-form--2' => '//form[@id="page-node-form--2"]//div[contains(@class, "field-name-field-ajax-test")]',
+ );
+ $button_name = $field_name . '_add_more';
+ $button_value = t('Add another item');
+ $button_xpath_suffix = '//input[@name="' . $button_name . '"]';
+ $field_items_xpath_suffix = '//input[@type="text"]';
+
+ // Ensure the initial page contains both node forms and the correct number
+ // of field items and "add more" button for the multi-valued field within
+ // each form.
+ $this->drupalGet('form-test/two-instances-of-same-form');
+ foreach ($field_xpaths as $form_html_id => $field_xpath) {
+ $this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == 1, t('Found the correct number of field items on the initial page.'));
+ $this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button on the initial page.'));
+ }
+ $this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
+
+ // Submit the "add more" button of each form twice. After each corresponding
+ // page update, ensure the same as above.
+ foreach ($field_xpaths as $form_html_id => $field_xpath) {
+ for ($i = 0; $i < 2; $i++) {
+ $this->drupalPostAJAX(NULL, array(), array($button_name => $button_value), 'system/ajax', array(), array(), $form_html_id);
+ $this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == $i+2, t('Found the correct number of field items after an AJAX submission.'));
+ $this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button after an AJAX submission.'));
+ $this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
+ }
+ }
+ }
+}
+
+/**
+ * Miscellaneous Ajax tests using ajax_test module.
+ */
+class AJAXElementValidation extends AJAXTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Miscellaneous AJAX tests',
+ 'description' => 'Various tests of AJAX behavior',
+ 'group' => 'AJAX',
+ );
+ }
+
+ /**
+ * Try to post an Ajax change to a form that has a validated element.
+ *
+ * The drivertext field is Ajax-enabled. An additional field is not, but
+ * is set to be a required field. In this test the required field is not
+ * filled in, and we want to see if the activation of the "drivertext"
+ * Ajax-enabled field fails due to the required field being empty.
+ */
+ function testAJAXElementValidation() {
+ $web_user = $this->drupalCreateUser();
+ $edit = array('drivertext' => t('some dumb text'));
+
+ // Post with 'drivertext' as the triggering element.
+ $post_result = $this->drupalPostAJAX('ajax_validation_test', $edit, 'drivertext');
+ // Look for a validation failure in the resultant JSON.
+ $this->assertNoText(t('Error message'), "No error message in resultant JSON");
+ $this->assertText('ajax_forms_test_validation_form_callback invoked', 'The correct callback was invoked');
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.info b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.info
new file mode 100644
index 0000000..67c45e2
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.info
@@ -0,0 +1,12 @@
+name = "AJAX form test mock module"
+description = "Test for AJAX form calls."
+core = 7.x
+package = Testing
+version = VERSION
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.module b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.module
new file mode 100644
index 0000000..2840422
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_forms_test.module
@@ -0,0 +1,502 @@
+<?php
+
+/**
+ * @file
+ * Simpletest mock module for Ajax forms testing.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function ajax_forms_test_menu() {
+ $items = array();
+ $items['ajax_forms_test_get_form'] = array(
+ 'title' => 'AJAX forms simple form test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ajax_forms_test_simple_form'),
+ 'access callback' => TRUE,
+ );
+ $items['ajax_forms_test_ajax_commands_form'] = array(
+ 'title' => 'AJAX forms AJAX commands test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ajax_forms_test_ajax_commands_form'),
+ 'access callback' => TRUE,
+ );
+ $items['ajax_validation_test'] = array(
+ 'title' => 'AJAX Validation Test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ajax_forms_test_validation_form'),
+ 'access callback' => TRUE,
+ );
+ $items['ajax_forms_test_lazy_load_form'] = array(
+ 'title' => 'AJAX forms lazy load test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ajax_forms_test_lazy_load_form'),
+ 'access callback' => TRUE,
+ );
+ return $items;
+}
+
+
+/**
+ * A basic form used to test form_state['values'] during callback.
+ */
+function ajax_forms_test_simple_form($form, &$form_state) {
+ $form = array();
+ $form['select'] = array(
+ '#type' => 'select',
+ '#options' => array(
+ 'red' => 'red',
+ 'green' => 'green',
+ 'blue' => 'blue'),
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_simple_form_select_callback',
+ ),
+ '#suffix' => '<div id="ajax_selected_color">No color yet selected</div>',
+ );
+
+ $form['checkbox'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Test checkbox'),
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_simple_form_checkbox_callback',
+ ),
+ '#suffix' => '<div id="ajax_checkbox_value">No action yet</div>',
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('submit'),
+ );
+ return $form;
+}
+
+/**
+ * Ajax callback triggered by select.
+ */
+function ajax_forms_test_simple_form_select_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_html('#ajax_selected_color', $form_state['values']['select']);
+ $commands[] = ajax_command_data('#ajax_selected_color', 'form_state_value_select', $form_state['values']['select']);
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback triggered by checkbox.
+ */
+function ajax_forms_test_simple_form_checkbox_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_html('#ajax_checkbox_value', (int) $form_state['values']['checkbox']);
+ $commands[] = ajax_command_data('#ajax_checkbox_value', 'form_state_value_select', (int) $form_state['values']['checkbox']);
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+
+/**
+ * Form to display the Ajax Commands.
+ */
+function ajax_forms_test_ajax_commands_form($form, &$form_state) {
+ $form = array();
+
+ // Shows the 'after' command with a callback generating commands.
+ $form['after_command_example'] = array(
+ '#value' => t("AJAX 'After': Click to put something after the div"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_after_callback',
+ ),
+ '#suffix' => '<div id="after_div">Something can be inserted after this</div>',
+ );
+
+ // Shows the 'alert' command.
+ $form['alert_command_example'] = array(
+ '#value' => t("AJAX 'Alert': Click to alert"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_alert_callback',
+ ),
+ );
+
+ // Shows the 'append' command.
+ $form['append_command_example'] = array(
+ '#value' => t("AJAX 'Append': Click to append something"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_append_callback',
+ ),
+ '#suffix' => '<div id="append_div">Append inside this div</div>',
+ );
+
+
+ // Shows the 'before' command.
+ $form['before_command_example'] = array(
+ '#value' => t("AJAX 'before': Click to put something before the div"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_before_callback',
+ ),
+ '#suffix' => '<div id="before_div">Insert something before this.</div>',
+ );
+
+ // Shows the 'changed' command without asterisk.
+ $form['changed_command_example'] = array(
+ '#value' => t("AJAX changed: Click to mark div changed."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_changed_callback',
+ ),
+ '#suffix' => '<div id="changed_div"> <div id="changed_div_mark_this">This div can be marked as changed or not.</div></div>',
+ );
+ // Shows the 'changed' command adding the asterisk.
+ $form['changed_command_asterisk_example'] = array(
+ '#value' => t("AJAX changed: Click to mark div changed with asterisk."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_changed_asterisk_callback',
+ ),
+ );
+
+ // Shows the Ajax 'css' command.
+ $form['css_command_example'] = array(
+ '#value' => t("Set the the '#box' div to be blue."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_css_callback',
+ ),
+ '#suffix' => '<div id="css_div" style="height: 50px; width: 50px; border: 1px solid black"> box</div>',
+ );
+
+
+ // Shows the Ajax 'data' command. But there is no use of this information,
+ // as this would require a javascript client to use the data.
+ $form['data_command_example'] = array(
+ '#value' => t("AJAX data command: Issue command."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_data_callback',
+ ),
+ '#suffix' => '<div id="data_div">Data attached to this div.</div>',
+ );
+
+ // Shows the Ajax 'invoke' command.
+ $form['invoke_command_example'] = array(
+ '#value' => t("AJAX invoke command: Invoke addClass() method."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_invoke_callback',
+ ),
+ '#suffix' => '<div id="invoke_div">Original contents</div>',
+ );
+
+ // Shows the Ajax 'html' command.
+ $form['html_command_example'] = array(
+ '#value' => t("AJAX html: Replace the HTML in a selector."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_html_callback',
+ ),
+ '#suffix' => '<div id="html_div">Original contents</div>',
+ );
+
+ // Shows the Ajax 'insert' command.
+ $form['insert_command_example'] = array(
+ '#value' => t("AJAX insert: Let client insert based on #ajax['method']."),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_insert_callback',
+ 'method' => 'prepend',
+ ),
+ '#suffix' => '<div id="insert_div">Original contents</div>',
+ );
+
+ // Shows the Ajax 'prepend' command.
+ $form['prepend_command_example'] = array(
+ '#value' => t("AJAX 'prepend': Click to prepend something"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_prepend_callback',
+ ),
+ '#suffix' => '<div id="prepend_div">Something will be prepended to this div. </div>',
+ );
+
+ // Shows the Ajax 'remove' command.
+ $form['remove_command_example'] = array(
+ '#value' => t("AJAX 'remove': Click to remove text"),
+ '#type' => 'submit',
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_remove_callback',
+ ),
+ '#suffix' => '<div id="remove_div"><div id="remove_text">text to be removed</div></div>',
+ );
+
+ // Shows the Ajax 'restripe' command.
+ $form['restripe_command_example'] = array(
+ '#type' => 'submit',
+ '#value' => t("AJAX 'restripe' command"),
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_restripe_callback',
+ ),
+ '#suffix' => '<div id="restripe_div">
+ <table id="restripe_table" style="border: 1px solid black" >
+ <tr id="table-first"><td>first row</td></tr>
+ <tr ><td>second row</td></tr>
+ </table>
+ </div>',
+ );
+
+ // Demonstrates the Ajax 'settings' command. The 'settings' command has
+ // nothing visual to "show", but it can be tested via SimpleTest and via
+ // Firebug.
+ $form['settings_command_example'] = array(
+ '#type' => 'submit',
+ '#value' => t("AJAX 'settings' command"),
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_advanced_commands_settings_callback',
+ ),
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+
+ return $form;
+}
+
+/**
+ * Ajax callback for 'after'.
+ */
+function ajax_forms_test_advanced_commands_after_callback($form, $form_state) {
+ $selector = '#after_div';
+
+ $commands = array();
+ $commands[] = ajax_command_after($selector, "This will be placed after");
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'alert'.
+ */
+function ajax_forms_test_advanced_commands_alert_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_alert("Alert");
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'append'.
+ */
+function ajax_forms_test_advanced_commands_append_callback($form, $form_state) {
+ $selector = '#append_div';
+ $commands = array();
+ $commands[] = ajax_command_append($selector, "Appended text");
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'before'.
+ */
+function ajax_forms_test_advanced_commands_before_callback($form, $form_state) {
+ $selector = '#before_div';
+
+ $commands = array();
+ $commands[] = ajax_command_before($selector, "Before text");
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'changed'.
+ */
+function ajax_forms_test_advanced_commands_changed_callback($form, $form_state) {
+ $commands[] = ajax_command_changed('#changed_div');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+/**
+ * Ajax callback for 'changed' with asterisk marking inner div.
+ */
+function ajax_forms_test_advanced_commands_changed_asterisk_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_changed('#changed_div', '#changed_div_mark_this');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'css'.
+ */
+function ajax_forms_test_advanced_commands_css_callback($form, $form_state) {
+ $selector = '#css_div';
+ $color = 'blue';
+
+ $commands = array();
+ $commands[] = ajax_command_css($selector, array('background-color' => $color));
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'data'.
+ */
+function ajax_forms_test_advanced_commands_data_callback($form, $form_state) {
+ $selector = '#data_div';
+
+ $commands = array();
+ $commands[] = ajax_command_data($selector, 'testkey', 'testvalue');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'invoke'.
+ */
+function ajax_forms_test_advanced_commands_invoke_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_invoke('#invoke_div', 'addClass', array('error'));
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'html'.
+ */
+function ajax_forms_test_advanced_commands_html_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_html('#html_div', 'replacement text');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'insert'.
+ */
+function ajax_forms_test_advanced_commands_insert_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_insert('#insert_div', 'insert replacement text');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'prepend'.
+ */
+function ajax_forms_test_advanced_commands_prepend_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_prepend('#prepend_div', "prepended text");
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'remove'.
+ */
+function ajax_forms_test_advanced_commands_remove_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_remove('#remove_text');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'restripe'.
+ */
+function ajax_forms_test_advanced_commands_restripe_callback($form, $form_state) {
+ $commands = array();
+ $commands[] = ajax_command_restripe('#restripe_table');
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * Ajax callback for 'settings'.
+ */
+function ajax_forms_test_advanced_commands_settings_callback($form, $form_state) {
+ $commands = array();
+ $setting['ajax_forms_test']['foo'] = 42;
+ $commands[] = ajax_command_settings($setting);
+ return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * This form and its related submit and callback functions demonstrate
+ * not validating another form element when a single Ajax element is triggered.
+ *
+ * The "drivertext" element is an Ajax-enabled textfield, free-form.
+ * The "required_field" element is a textfield marked required.
+ *
+ * The correct behavior is that the Ajax-enabled drivertext element should
+ * be able to trigger without causing validation of the "required_field".
+ */
+function ajax_forms_test_validation_form($form, &$form_state) {
+
+ $form['drivertext'] = array(
+ '#title' => t('AJAX-enabled textfield.'),
+ '#description' => t("When this one AJAX-triggers and the spare required field is empty, you should not get an error."),
+ '#type' => 'textfield',
+ '#default_value' => !empty($form_state['values']['drivertext']) ? $form_state['values']['drivertext'] : "",
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_validation_form_callback',
+ 'wrapper' => 'message_area',
+ 'method' => 'replace',
+ ),
+ '#suffix' => '<div id="message_area"></div>',
+ );
+
+ $form['spare_required_field'] = array(
+ '#title' => t("Spare Required Field"),
+ '#type' => 'textfield',
+ '#required' => TRUE,
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+
+ return $form;
+}
+/**
+ * Submit handler for the validation form.
+ */
+function ajax_forms_test_validation_form_submit($form, $form_state) {
+ drupal_set_message(t("Validation form submitted"));
+}
+
+/**
+ * Ajax callback for the 'drivertext' element of the validation form.
+ */
+function ajax_forms_test_validation_form_callback($form, $form_state) {
+ drupal_set_message("ajax_forms_test_validation_form_callback invoked");
+ drupal_set_message(t("Callback: drivertext=%drivertext, spare_required_field=%spare_required_field", array('%drivertext' => $form_state['values']['drivertext'], '%spare_required_field' => $form_state['values']['spare_required_field'])));
+ return '<div id="message_area">ajax_forms_test_validation_form_callback at ' . date('c') . '</div>';
+}
+
+/**
+ * Form builder: Builds a form that triggers a simple AJAX callback.
+ */
+function ajax_forms_test_lazy_load_form($form, &$form_state) {
+ $form['add_files'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => FALSE,
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_lazy_load_form_ajax',
+ ),
+ );
+ return $form;
+}
+
+/**
+ * Form submit handler: Adds JavaScript and CSS that wasn't on the original form.
+ */
+function ajax_forms_test_lazy_load_form_submit($form, &$form_state) {
+ if ($form_state['values']['add_files']) {
+ drupal_add_js(array('ajax_forms_test_lazy_load_form_submit' => 'executed'), 'setting');
+ drupal_add_css(drupal_get_path('module', 'system') . '/system.admin.css');
+ drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
+ }
+ $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * AJAX callback for the ajax_forms_test_lazy_load_form() form.
+ *
+ * This function returns nothing, because all we're interested in testing is
+ * ajax_render() adding commands for JavaScript and CSS added during the page
+ * request, such as the ones added in ajax_forms_test_lazy_load_form_submit().
+ */
+function ajax_forms_test_lazy_load_form_ajax($form, &$form_state) {
+ return NULL;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.info b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.info
new file mode 100644
index 0000000..0dab7ed
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.info
@@ -0,0 +1,12 @@
+name = AJAX Test
+description = Support module for AJAX framework tests.
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.module b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.module
new file mode 100644
index 0000000..21be019
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/ajax_test.module
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Helper module for Ajax framework tests.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function ajax_test_menu() {
+ $items['ajax-test/render'] = array(
+ 'title' => 'ajax_render',
+ 'page callback' => 'ajax_test_render',
+ 'delivery callback' => 'ajax_deliver',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+ $items['ajax-test/render-error'] = array(
+ 'title' => 'ajax_render_error',
+ 'page callback' => 'ajax_test_error',
+ 'delivery callback' => 'ajax_deliver',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+ $items['ajax-test/link'] = array(
+ 'title' => 'AJAX Link',
+ 'page callback' => 'ajax_test_link',
+ 'access callback' => TRUE,
+ );
+ return $items;
+}
+
+/**
+ * Implements hook_system_theme_info().
+ */
+function ajax_test_system_theme_info() {
+ $themes['test_theme'] = drupal_get_path('module', 'ajax_test') . '/themes/test_theme/test_theme.info';
+ return $themes;
+}
+
+/**
+ * Menu callback; Return an element suitable for use by ajax_deliver().
+ *
+ * Additionally ensures that ajax_render() incorporates JavaScript settings
+ * generated during the page request by invoking drupal_add_js() with a dummy
+ * setting.
+ */
+function ajax_test_render() {
+ drupal_add_js(array('ajax' => 'test'), 'setting');
+ return array('#type' => 'ajax', '#commands' => array());
+}
+
+/**
+ * Menu callback; Returns Ajax element with #error property set.
+ */
+function ajax_test_error() {
+ $message = '';
+ if (!empty($_GET['message'])) {
+ $message = $_GET['message'];
+ }
+ return array('#type' => 'ajax', '#error' => $message);
+}
+
+/**
+ * Menu callback; Renders a #type link with #ajax.
+ */
+function ajax_test_link() {
+ $build['link'] = array(
+ '#type' => 'link',
+ '#title' => 'Show help',
+ '#href' => 'filter/tips',
+ '#ajax' => array(
+ 'wrapper' => 'block-system-main',
+ ),
+ );
+ return $build;
+}
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch.test
new file mode 100644
index 0000000..e41bc92
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch.test
@@ -0,0 +1,403 @@
+<?php
+
+/**
+ * @file
+ * Tests for the Batch API.
+ */
+
+/**
+ * Tests for the Batch API.
+ */
+class BatchProcessingTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Batch processing',
+ 'description' => 'Test batch processing in form and non-form workflow.',
+ 'group' => 'Batch API',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('batch_test');
+ }
+
+ /**
+ * Test batches triggered outside of form submission.
+ */
+ function testBatchNoForm() {
+ // Displaying the page triggers batch 1.
+ $this->drupalGet('batch-test/no-form');
+ $this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+ }
+
+ /**
+ * Test batches defined in a form submit handler.
+ */
+ function testBatchForm() {
+ // Batch 0: no operation.
+ $edit = array('batch' => 'batch_0');
+ $this->drupalPost('batch-test/simple', $edit, 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_0'), t('Batch with no operation performed successfully.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+
+ // Batch 1: several simple operations.
+ $edit = array('batch' => 'batch_1');
+ $this->drupalPost('batch-test/simple', $edit, 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch with simple operations performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+
+ // Batch 2: one multistep operation.
+ $edit = array('batch' => 'batch_2');
+ $this->drupalPost('batch-test/simple', $edit, 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_2'), t('Batch with multistep operation performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+
+ // Batch 3: simple + multistep combined.
+ $edit = array('batch' => 'batch_3');
+ $this->drupalPost('batch-test/simple', $edit, 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_3'), t('Batch with simple and multistep operations performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_3'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+
+ // Batch 4: nested batch.
+ $edit = array('batch' => 'batch_4');
+ $this->drupalPost('batch-test/simple', $edit, 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_4'), t('Nested batch performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_4'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+ }
+
+ /**
+ * Test batches defined in a multistep form.
+ */
+ function testBatchFormMultistep() {
+ $this->drupalGet('batch-test/multistep');
+ $this->assertText('step 1', t('Form is displayed in step 1.'));
+
+ // First step triggers batch 1.
+ $this->drupalPost(NULL, array(), 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch for step 1 performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
+ $this->assertText('step 2', t('Form is displayed in step 2.'));
+
+ // Second step triggers batch 2.
+ $this->drupalPost(NULL, array(), 'Submit');
+ $this->assertBatchMessages($this->_resultMessages('batch_2'), t('Batch for step 2 performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+ }
+
+ /**
+ * Test batches defined in different submit handlers on the same form.
+ */
+ function testBatchFormMultipleBatches() {
+ // Batches 1, 2 and 3 are triggered in sequence by different submit
+ // handlers. Each submit handler modify the submitted 'value'.
+ $value = rand(0, 255);
+ $edit = array('value' => $value);
+ $this->drupalPost('batch-test/chained', $edit, 'Submit');
+ // Check that result messages are present and in the correct order.
+ $this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.'));
+ // The stack contains execution order of batch callbacks and submit
+ // hanlders and logging of corresponding $form_state[{values'].
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('chained', $value), t('Execution order was correct, and $form_state is correctly persisted.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+ }
+
+ /**
+ * Test batches defined in a programmatically submitted form.
+ *
+ * Same as above, but the form is submitted through drupal_form_execute().
+ */
+ function testBatchFormProgrammatic() {
+ // Batches 1, 2 and 3 are triggered in sequence by different submit
+ // handlers. Each submit handler modify the submitted 'value'.
+ $value = rand(0, 255);
+ $this->drupalGet('batch-test/programmatic/' . $value);
+ // Check that result messages are present and in the correct order.
+ $this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.'));
+ // The stack contains execution order of batch callbacks and submit
+ // hanlders and logging of corresponding $form_state[{values'].
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('chained', $value), t('Execution order was correct, and $form_state is correctly persisted.'));
+ $this->assertText('Got out of a programmatic batched form.', t('Page execution continues normally.'));
+ }
+
+ /**
+ * Test that drupal_form_submit() can run within a batch operation.
+ */
+ function testDrupalFormSubmitInBatch() {
+ // Displaying the page triggers a batch that programmatically submits a
+ // form.
+ $value = rand(0, 255);
+ $this->drupalGet('batch-test/nested-programmatic/' . $value);
+ $this->assertEqual(batch_test_stack(), array('mock form submitted with value = ' . $value), t('drupal_form_submit() ran successfully within a batch operation.'));
+ }
+
+ /**
+ * Test batches that return $context['finished'] > 1 do in fact complete.
+ * See http://drupal.org/node/600836
+ */
+ function testBatchLargePercentage() {
+ // Displaying the page triggers batch 5.
+ $this->drupalGet('batch-test/large-percentage');
+ $this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.'));
+ $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_5'), t('Execution order was correct.'));
+ $this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
+ }
+
+
+ /**
+ * Will trigger a pass if the texts were found in order in the raw content.
+ *
+ * @param $texts
+ * Array of raw strings to look for .
+ * @param $message
+ * Message to display.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ function assertBatchMessages($texts, $message) {
+ $pattern = '|' . implode('.*', $texts) .'|s';
+ return $this->assertPattern($pattern, $message);
+ }
+
+ /**
+ * Helper function: return expected execution stacks for the test batches.
+ */
+ function _resultStack($id, $value = 0) {
+ $stack = array();
+ switch ($id) {
+ case 'batch_1':
+ for ($i = 1; $i <= 10; $i++) {
+ $stack[] = "op 1 id $i";
+ }
+ break;
+
+ case 'batch_2':
+ for ($i = 1; $i <= 10; $i++) {
+ $stack[] = "op 2 id $i";
+ }
+ break;
+
+ case 'batch_3':
+ for ($i = 1; $i <= 5; $i++) {
+ $stack[] = "op 1 id $i";
+ }
+ for ($i = 1; $i <= 5; $i++) {
+ $stack[] = "op 2 id $i";
+ }
+ for ($i = 6; $i <= 10; $i++) {
+ $stack[] = "op 1 id $i";
+ }
+ for ($i = 6; $i <= 10; $i++) {
+ $stack[] = "op 2 id $i";
+ }
+ break;
+
+ case 'batch_4':
+ for ($i = 1; $i <= 5; $i++) {
+ $stack[] = "op 1 id $i";
+ }
+ $stack[] = 'setting up batch 2';
+ for ($i = 6; $i <= 10; $i++) {
+ $stack[] = "op 1 id $i";
+ }
+ $stack = array_merge($stack, $this->_resultStack('batch_2'));
+ break;
+
+ case 'batch_5':
+ for ($i = 1; $i <= 10; $i++) {
+ $stack[] = "op 5 id $i";
+ }
+ break;
+
+ case 'chained':
+ $stack[] = 'submit handler 1';
+ $stack[] = 'value = ' . $value;
+ $stack = array_merge($stack, $this->_resultStack('batch_1'));
+ $stack[] = 'submit handler 2';
+ $stack[] = 'value = ' . ($value + 1);
+ $stack = array_merge($stack, $this->_resultStack('batch_2'));
+ $stack[] = 'submit handler 3';
+ $stack[] = 'value = ' . ($value + 2);
+ $stack[] = 'submit handler 4';
+ $stack[] = 'value = ' . ($value + 3);
+ $stack = array_merge($stack, $this->_resultStack('batch_3'));
+ break;
+ }
+ return $stack;
+ }
+
+ /**
+ * Helper function: return expected result messages for the test batches.
+ */
+ function _resultMessages($id) {
+ $messages = array();
+
+ switch ($id) {
+ case 'batch_0':
+ $messages[] = 'results for batch 0<br />none';
+ break;
+
+ case 'batch_1':
+ $messages[] = 'results for batch 1<br />op 1: processed 10 elements';
+ break;
+
+ case 'batch_2':
+ $messages[] = 'results for batch 2<br />op 2: processed 10 elements';
+ break;
+
+ case 'batch_3':
+ $messages[] = 'results for batch 3<br />op 1: processed 10 elements<br />op 2: processed 10 elements';
+ break;
+
+ case 'batch_4':
+ $messages[] = 'results for batch 4<br />op 1: processed 10 elements';
+ $messages = array_merge($messages, $this->_resultMessages('batch_2'));
+ break;
+
+ case 'batch_5':
+ $messages[] = 'results for batch 5<br />op 1: processed 10 elements. $context[\'finished\'] > 1 returned from batch process, with success.';
+ break;
+
+ case 'chained':
+ $messages = array_merge($messages, $this->_resultMessages('batch_1'));
+ $messages = array_merge($messages, $this->_resultMessages('batch_2'));
+ $messages = array_merge($messages, $this->_resultMessages('batch_3'));
+ break;
+ }
+ return $messages;
+ }
+}
+
+/**
+ * Tests for the Batch API Progress page.
+ */
+class BatchPageTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Batch progress page',
+ 'description' => 'Test the content of the progress page.',
+ 'group' => 'Batch API',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('batch_test');
+ }
+
+ /**
+ * Tests that the batch API progress page uses the correct theme.
+ */
+ function testBatchProgressPageTheme() {
+ // Make sure that the page which starts the batch (an administrative page)
+ // is using a different theme than would normally be used by the batch API.
+ variable_set('theme_default', 'bartik');
+ variable_set('admin_theme', 'seven');
+ // Log in as an administrator who can see the administrative theme.
+ $admin_user = $this->drupalCreateUser(array('view the administration theme'));
+ $this->drupalLogin($admin_user);
+ // Visit an administrative page that runs a test batch, and check that the
+ // theme that was used during batch execution (which the batch callback
+ // function saved as a variable) matches the theme used on the
+ // administrative page.
+ $this->drupalGet('admin/batch-test/test-theme');
+ // The stack should contain the name of the theme used on the progress
+ // page.
+ $this->assertEqual(batch_test_stack(), array('seven'), t('A progressive batch correctly uses the theme of the page that started the batch.'));
+ }
+}
+
+/**
+ * Tests the function _batch_api_percentage() to make sure that the rounding
+ * works properly in all cases.
+ */
+class BatchPercentagesUnitTestCase extends DrupalUnitTestCase {
+ protected $testCases = array();
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Batch percentages',
+ 'description' => 'Unit tests of progress percentage rounding.',
+ 'group' => 'Batch API',
+ );
+ }
+
+ function setUp() {
+ // Set up an array of test cases, where the expected values are the keys,
+ // and the values are arrays with the keys 'total' and 'current',
+ // corresponding with the function parameters of _batch_api_percentage().
+ $this->testCases = array(
+ // 1/2 is 50%.
+ '50' => array('total' => 2, 'current' => 1),
+ // Though we should never encounter a case where the current set is set
+ // 0, if we did, we should get 0%.
+ '0' => array('total' => 3, 'current' => 0),
+ // 1/3 is closer to 33% than to 34%.
+ '33' => array('total' => 3, 'current' => 1),
+ // 2/3 is closer to 67% than to 66%.
+ '67' => array('total' => 3, 'current' => 2),
+ // 1/199 should round up to 1%.
+ '1' => array('total' => 199, 'current' => 1),
+ // 198/199 should round down to 99%.
+ '99' => array('total' => 199, 'current' => 198),
+ // 199/200 would have rounded up to 100%, which would give the false
+ // impression of being finished, so we add another digit and should get
+ // 99.5%.
+ '99.5' => array('total' => 200, 'current' => 199),
+ // The same logic holds for 1/200: we should get 0.5%.
+ '0.5' => array('total' => 200, 'current' => 1),
+ // Numbers that come out evenly, such as 50/200, should be forced to have
+ // extra digits for consistancy.
+ '25.0' => array('total' => 200, 'current' => 50),
+ // Regardless of number of digits we're using, 100% should always just be
+ // 100%.
+ '100' => array('total' => 200, 'current' => 200),
+ // 1998/1999 should similarly round down to 99.9%.
+ '99.9' => array('total' => 1999, 'current' => 1998),
+ // 1999/2000 should add another digit and go to 99.95%.
+ '99.95' => array('total' => 2000, 'current' => 1999),
+ // 19999/20000 should add yet another digit and go to 99.995%.
+ '99.995' => array('total' => 20000, 'current' => 19999),
+ // The next five test cases simulate a batch with a single operation
+ // ('total' equals 1) that takes several steps to complete. Within the
+ // operation, we imagine that there are 501 items to process, and 100 are
+ // completed during each step. The percentages we get back should be
+ // rounded the usual way for the first few passes (i.e., 20%, 40%, etc.),
+ // but for the last pass through, when 500 out of 501 items have been
+ // processed, we do not want to round up to 100%, since that would
+ // erroneously indicate that the processing is complete.
+ '20' => array('total' => 1, 'current' => 100/501),
+ '40' => array('total' => 1, 'current' => 200/501),
+ '60' => array('total' => 1, 'current' => 300/501),
+ '80' => array('total' => 1, 'current' => 400/501),
+ '99.8' => array('total' => 1, 'current' => 500/501),
+ );
+ require_once DRUPAL_ROOT . '/includes/batch.inc';
+ parent::setUp();
+ }
+
+ /**
+ * Test the _batch_api_percentage() function.
+ */
+ function testBatchPercentages() {
+ foreach ($this->testCases as $expected_result => $arguments) {
+ // PHP sometimes casts numeric strings that are array keys to integers,
+ // cast them back here.
+ $expected_result = (string) $expected_result;
+ $total = $arguments['total'];
+ $current = $arguments['current'];
+ $actual_result = _batch_api_percentage($total, $current);
+ if ($actual_result === $expected_result) {
+ $this->pass(t('Expected the batch api percentage at the state @numerator/@denominator to be @expected%, and got @actual%.', array('@numerator' => $current, '@denominator' => $total, '@expected' => $expected_result, '@actual' => $actual_result)));
+ }
+ else {
+ $this->fail(t('Expected the batch api percentage at the state @numerator/@denominator to be @expected%, but got @actual%.', array('@numerator' => $current, '@denominator' => $total, '@expected' => $expected_result, '@actual' => $actual_result)));
+ }
+ }
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.callbacks.inc b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.callbacks.inc
new file mode 100644
index 0000000..75e6655
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.callbacks.inc
@@ -0,0 +1,141 @@
+<?php
+
+
+/**
+ * @file
+ * Batch callbacks for the Batch API tests.
+ */
+
+/**
+ * Simple batch operation.
+ */
+function _batch_test_callback_1($id, $sleep, &$context) {
+ // No-op, but ensure the batch take a couple iterations.
+ // Batch needs time to run for the test, so sleep a bit.
+ usleep($sleep);
+ // Track execution, and store some result for post-processing in the
+ // 'finished' callback.
+ batch_test_stack("op 1 id $id");
+ $context['results'][1][] = $id;
+}
+
+/**
+ * Multistep batch operation.
+ */
+function _batch_test_callback_2($start, $total, $sleep, &$context) {
+ // Initialize context with progress information.
+ if (!isset($context['sandbox']['current'])) {
+ $context['sandbox']['current'] = $start;
+ $context['sandbox']['count'] = 0;
+ }
+
+ // Process by groups of 5 (arbitrary value).
+ $limit = 5;
+ for ($i = 0; $i < $limit && $context['sandbox']['count'] < $total; $i++) {
+ // No-op, but ensure the batch take a couple iterations.
+ // Batch needs time to run for the test, so sleep a bit.
+ usleep($sleep);
+ // Track execution, and store some result for post-processing in the
+ // 'finished' callback.
+ $id = $context['sandbox']['current'] + $i;
+ batch_test_stack("op 2 id $id");
+ $context['results'][2][] = $id;
+
+ // Update progress information.
+ $context['sandbox']['count']++;
+ }
+ $context['sandbox']['current'] += $i;
+
+ // Inform batch engine about progress.
+ if ($context['sandbox']['count'] != $total) {
+ $context['finished'] = $context['sandbox']['count'] / $total;
+ }
+}
+
+/**
+ * Simple batch operation.
+ */
+function _batch_test_callback_5($id, $sleep, &$context) {
+ // No-op, but ensure the batch take a couple iterations.
+ // Batch needs time to run for the test, so sleep a bit.
+ usleep($sleep);
+ // Track execution, and store some result for post-processing in the
+ // 'finished' callback.
+ batch_test_stack("op 5 id $id");
+ $context['results'][5][] = $id;
+ // This test is to test finished > 1
+ $context['finished'] = 3.14;
+}
+
+/**
+ * Batch operation setting up its own batch.
+ */
+function _batch_test_nested_batch_callback() {
+ batch_test_stack('setting up batch 2');
+ batch_set(_batch_test_batch_2());
+}
+
+/**
+ * Common 'finished' callbacks for batches 1 to 4.
+ */
+function _batch_test_finished_helper($batch_id, $success, $results, $operations) {
+ $messages = array("results for batch $batch_id");
+ if ($results) {
+ foreach ($results as $op => $op_results) {
+ $messages[] = 'op '. $op . ': processed ' . count($op_results) . ' elements';
+ }
+ }
+ else {
+ $messages[] = 'none';
+ }
+
+ if (!$success) {
+ // A fatal error occurred during the processing.
+ $error_operation = reset($operations);
+ $messages[] = t('An error occurred while processing @op with arguments:<br/>@args', array('@op' => $error_operation[0], '@args' => print_r($error_operation[1], TRUE)));
+ }
+
+ drupal_set_message(implode('<br />', $messages));
+}
+
+/**
+ * 'finished' callback for batch 0.
+ */
+function _batch_test_finished_0($success, $results, $operations) {
+ _batch_test_finished_helper(0, $success, $results, $operations);
+}
+
+/**
+ * 'finished' callback for batch 1.
+ */
+function _batch_test_finished_1($success, $results, $operations) {
+ _batch_test_finished_helper(1, $success, $results, $operations);
+}
+
+/**
+ * 'finished' callback for batch 2.
+ */
+function _batch_test_finished_2($success, $results, $operations) {
+ _batch_test_finished_helper(2, $success, $results, $operations);
+}
+
+/**
+ * 'finished' callback for batch 3.
+ */
+function _batch_test_finished_3($success, $results, $operations) {
+ _batch_test_finished_helper(3, $success, $results, $operations);
+}
+
+/**
+ * 'finished' callback for batch 4.
+ */
+function _batch_test_finished_4($success, $results, $operations) {
+ _batch_test_finished_helper(4, $success, $results, $operations);
+}
+
+/**
+ * 'finished' callback for batch 5.
+ */
+function _batch_test_finished_5($success, $results, $operations) {
+ _batch_test_finished_helper(5, $success, $results, $operations);
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.info b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.info
new file mode 100644
index 0000000..c69cd11
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.info
@@ -0,0 +1,12 @@
+name = "Batch API test"
+description = "Support module for Batch API tests."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.module b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.module
new file mode 100644
index 0000000..1200e76
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/batch_test.module
@@ -0,0 +1,513 @@
+<?php
+
+/**
+ * @file
+ * Helper module for the Batch API tests.
+ */
+
+/**
+ * Implement hook_menu().
+ */
+function batch_test_menu() {
+ $items = array();
+
+ $items['batch-test'] = array(
+ 'title' => 'Batch test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('batch_test_simple_form'),
+ 'access callback' => TRUE,
+ );
+ // Simple form: one submit handler, setting a batch.
+ $items['batch-test/simple'] = array(
+ 'title' => 'Simple',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => 0,
+ );
+ // Multistep form: two steps, each setting a batch.
+ $items['batch-test/multistep'] = array(
+ 'title' => 'Multistep',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('batch_test_multistep_form'),
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 1,
+ );
+ // Chained form: four submit handlers, several of which set a batch.
+ $items['batch-test/chained'] = array(
+ 'title' => 'Chained',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('batch_test_chained_form'),
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 2,
+ );
+ // Programmatic form: the page submits the 'Chained' form through
+ // drupal_form_submit().
+ $items['batch-test/programmatic'] = array(
+ 'title' => 'Programmatic',
+ 'page callback' => 'batch_test_programmatic',
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 3,
+ );
+ // No form: fire a batch simply by accessing a page.
+ $items['batch-test/no-form'] = array(
+ 'title' => 'Simple page',
+ 'page callback' => 'batch_test_no_form',
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 4,
+ );
+ // No form: fire a batch; return > 100% complete
+ $items['batch-test/large-percentage'] = array(
+ 'title' => 'Simple page with batch over 100% complete',
+ 'page callback' => 'batch_test_large_percentage',
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 5,
+ );
+ // Tests programmatic form submission within a batch operation.
+ $items['batch-test/nested-programmatic'] = array(
+ 'title' => 'Nested programmatic',
+ 'page callback' => 'batch_test_nested_drupal_form_submit',
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 6,
+ );
+ // Landing page to test redirects.
+ $items['batch-test/redirect'] = array(
+ 'title' => 'Redirect',
+ 'page callback' => 'batch_test_redirect_page',
+ 'access callback' => TRUE,
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 7,
+ );
+ // This item lives under 'admin' so that the page uses the admin theme.
+ $items['admin/batch-test/test-theme'] = array(
+ 'page callback' => 'batch_test_theme_batch',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
+ return $items;
+}
+
+/**
+ * Simple form.
+ */
+function batch_test_simple_form() {
+ $form['batch'] = array(
+ '#type' => 'select',
+ '#title' => 'Choose batch',
+ '#options' => array(
+ 'batch_0' => 'batch 0',
+ 'batch_1' => 'batch 1',
+ 'batch_2' => 'batch 2',
+ 'batch_3' => 'batch 3',
+ 'batch_4' => 'batch 4',
+ ),
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Submit',
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler for the simple form.
+ */
+function batch_test_simple_form_submit($form, &$form_state) {
+ batch_test_stack(NULL, TRUE);
+
+ $function = '_batch_test_' . $form_state['values']['batch'];
+ batch_set($function());
+
+ $form_state['redirect'] = 'batch-test/redirect';
+}
+
+
+/**
+ * Multistep form.
+ */
+function batch_test_multistep_form($form, &$form_state) {
+ if (empty($form_state['storage']['step'])) {
+ $form_state['storage']['step'] = 1;
+ }
+
+ $form['step_display'] = array(
+ '#markup' => 'step ' . $form_state['storage']['step'] . '<br/>',
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Submit',
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler for the multistep form.
+ */
+function batch_test_multistep_form_submit($form, &$form_state) {
+ batch_test_stack(NULL, TRUE);
+
+ switch ($form_state['storage']['step']) {
+ case 1:
+ batch_set(_batch_test_batch_1());
+ break;
+ case 2:
+ batch_set(_batch_test_batch_2());
+ break;
+ }
+
+ if ($form_state['storage']['step'] < 2) {
+ $form_state['storage']['step']++;
+ $form_state['rebuild'] = TRUE;
+ }
+
+ // This will only be effective on the last step.
+ $form_state['redirect'] = 'batch-test/redirect';
+}
+
+/**
+ * Form with chained submit callbacks.
+ */
+function batch_test_chained_form() {
+ // This value is used to test that $form_state persists through batched
+ // submit handlers.
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => 'Value',
+ '#default_value' => 1,
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Submit',
+ );
+ $form['#submit'] = array(
+ 'batch_test_chained_form_submit_1',
+ 'batch_test_chained_form_submit_2',
+ 'batch_test_chained_form_submit_3',
+ 'batch_test_chained_form_submit_4',
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler #1 for the chained form.
+ */
+function batch_test_chained_form_submit_1($form, &$form_state) {
+ batch_test_stack(NULL, TRUE);
+
+ batch_test_stack('submit handler 1');
+ batch_test_stack('value = ' . $form_state['values']['value']);
+
+ $form_state['values']['value']++;
+ batch_set(_batch_test_batch_1());
+
+ // This redirect should not be taken into account.
+ $form_state['redirect'] = 'should/be/discarded';
+}
+
+/**
+ * Submit handler #2 for the chained form.
+ */
+function batch_test_chained_form_submit_2($form, &$form_state) {
+ batch_test_stack('submit handler 2');
+ batch_test_stack('value = ' . $form_state['values']['value']);
+
+ $form_state['values']['value']++;
+ batch_set(_batch_test_batch_2());
+
+ // This redirect should not be taken into account.
+ $form_state['redirect'] = 'should/be/discarded';
+}
+
+/**
+ * Submit handler #3 for the chained form.
+ */
+function batch_test_chained_form_submit_3($form, &$form_state) {
+ batch_test_stack('submit handler 3');
+ batch_test_stack('value = ' . $form_state['values']['value']);
+
+ $form_state['values']['value']++;
+
+ // This redirect should not be taken into account.
+ $form_state['redirect'] = 'should/be/discarded';
+}
+
+/**
+ * Submit handler #4 for the chained form.
+ */
+function batch_test_chained_form_submit_4($form, &$form_state) {
+ batch_test_stack('submit handler 4');
+ batch_test_stack('value = ' . $form_state['values']['value']);
+
+ $form_state['values']['value']++;
+ batch_set(_batch_test_batch_3());
+
+ // This is the redirect that should prevail.
+ $form_state['redirect'] = 'batch-test/redirect';
+}
+
+/**
+ * Menu callback: programmatically submits the 'Chained' form.
+ */
+function batch_test_programmatic($value = 1) {
+ $form_state = array(
+ 'values' => array('value' => $value)
+ );
+ drupal_form_submit('batch_test_chained_form', $form_state);
+ return 'Got out of a programmatic batched form.';
+}
+
+/**
+ * Menu callback: programmatically submits a form within a batch.
+ */
+function batch_test_nested_drupal_form_submit($value = 1) {
+ // Set the batch and process it.
+ $batch['operations'] = array(
+ array('_batch_test_nested_drupal_form_submit_callback', array($value)),
+ );
+ batch_set($batch);
+ batch_process('batch-test/redirect');
+}
+
+/**
+ * Batch operation: submits form_test_mock_form using drupal_form_submit().
+ */
+function _batch_test_nested_drupal_form_submit_callback($value) {
+ $state['values']['test_value'] = $value;
+ drupal_form_submit('batch_test_mock_form', $state);
+}
+
+/**
+ * A simple form with a textfield and submit button.
+ */
+function batch_test_mock_form($form, $form_state) {
+ $form['test_value'] = array(
+ '#type' => 'textfield',
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler for the batch_test_mock form.
+ */
+function batch_test_mock_form_submit($form, &$form_state) {
+ batch_test_stack('mock form submitted with value = ' . $form_state['values']['test_value']);
+}
+
+/**
+ * Menu callback: fire a batch process without a form submission.
+ */
+function batch_test_no_form() {
+ batch_test_stack(NULL, TRUE);
+
+ batch_set(_batch_test_batch_1());
+ batch_process('batch-test/redirect');
+}
+
+/**
+ * Menu callback: fire a batch process without a form submission.
+ */
+function batch_test_large_percentage() {
+ batch_test_stack(NULL, TRUE);
+
+ batch_set(_batch_test_batch_5());
+ batch_process('batch-test/redirect');
+}
+
+/**
+ * Menu callback: successful redirection.
+ */
+function batch_test_redirect_page() {
+ return 'Redirection successful.';
+}
+
+/**
+ * Batch 0: no operation.
+ */
+function _batch_test_batch_0() {
+ $batch = array(
+ 'operations' => array(),
+ 'finished' => '_batch_test_finished_0',
+ 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Batch 1: repeats a simple operation.
+ *
+ * Operations: op 1 from 1 to 10.
+ */
+function _batch_test_batch_1() {
+ // Ensure the batch takes at least two iterations.
+ $total = 10;
+ $sleep = (1000000 / $total) * 2;
+
+ $operations = array();
+ for ($i = 1; $i <= $total; $i++) {
+ $operations[] = array('_batch_test_callback_1', array($i, $sleep));
+ }
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_batch_test_finished_1',
+ 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Batch 2: single multistep operation.
+ *
+ * Operations: op 2 from 1 to 10.
+ */
+function _batch_test_batch_2() {
+ // Ensure the batch takes at least two iterations.
+ $total = 10;
+ $sleep = (1000000 / $total) * 2;
+
+ $operations = array(
+ array('_batch_test_callback_2', array(1, $total, $sleep)),
+ );
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_batch_test_finished_2',
+ 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Batch 3: both single and multistep operations.
+ *
+ * Operations:
+ * - op 1 from 1 to 5,
+ * - op 2 from 1 to 5,
+ * - op 1 from 6 to 10,
+ * - op 2 from 6 to 10.
+ */
+function _batch_test_batch_3() {
+ // Ensure the batch takes at least two iterations.
+ $total = 10;
+ $sleep = (1000000 / $total) * 2;
+
+ $operations = array();
+ for ($i = 1; $i <= round($total / 2); $i++) {
+ $operations[] = array('_batch_test_callback_1', array($i, $sleep));
+ }
+ $operations[] = array('_batch_test_callback_2', array(1, $total / 2, $sleep));
+ for ($i = round($total / 2) + 1; $i <= $total; $i++) {
+ $operations[] = array('_batch_test_callback_1', array($i, $sleep));
+ }
+ $operations[] = array('_batch_test_callback_2', array(6, $total / 2, $sleep));
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_batch_test_finished_3',
+ 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Batch 4: batch within a batch.
+ *
+ * Operations:
+ * - op 1 from 1 to 5,
+ * - set batch 2 (op 2 from 1 to 10, should run at the end)
+ * - op 1 from 6 to 10,
+ */
+function _batch_test_batch_4() {
+ // Ensure the batch takes at least two iterations.
+ $total = 10;
+ $sleep = (1000000 / $total) * 2;
+
+ $operations = array();
+ for ($i = 1; $i <= round($total / 2); $i++) {
+ $operations[] = array('_batch_test_callback_1', array($i, $sleep));
+ }
+ $operations[] = array('_batch_test_nested_batch_callback', array());
+ for ($i = round($total / 2) + 1; $i <= $total; $i++) {
+ $operations[] = array('_batch_test_callback_1', array($i, $sleep));
+ }
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_batch_test_finished_4',
+ 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Batch 5: repeats a simple operation.
+ *
+ * Operations: op 1 from 1 to 10.
+ */
+function _batch_test_batch_5() {
+ // Ensure the batch takes at least two iterations.
+ $total = 10;
+ $sleep = (1000000 / $total) * 2;
+
+ $operations = array();
+ for ($i = 1; $i <= $total; $i++) {
+ $operations[] = array('_batch_test_callback_5', array($i, $sleep));
+ }
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_batch_test_finished_5',
+ 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
+ );
+ return $batch;
+}
+
+/**
+ * Menu callback: run a batch for testing theme used on the progress page.
+ */
+function batch_test_theme_batch() {
+ batch_test_stack(NULL, TRUE);
+ $batch = array(
+ 'operations' => array(
+ array('_batch_test_theme_callback', array()),
+ ),
+ );
+ batch_set($batch);
+ batch_process('batch-test/redirect');
+}
+
+/**
+ * Batch callback function for testing the theme used on the progress page.
+ */
+function _batch_test_theme_callback() {
+ // Because drupalGet() steps through the full progressive batch before
+ // returning control to the test function, we cannot test that the correct
+ // theme is being used on the batch processing page by viewing that page
+ // directly. Instead, we save the theme being used in a variable here, so
+ // that it can be loaded and inspected in the thread running the test.
+ global $theme;
+ batch_test_stack($theme);
+}
+
+/**
+ * Helper function: store or retrieve traced execution data.
+ */
+function batch_test_stack($data = NULL, $reset = FALSE) {
+ if ($reset) {
+ variable_del('batch_test_stack');
+ }
+ if (!isset($data)) {
+ return variable_get('batch_test_stack', array());
+ }
+ $stack = variable_get('batch_test_stack', array());
+ $stack[] = $data;
+ variable_set('batch_test_stack', $stack);
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/bootstrap.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/bootstrap.test
new file mode 100644
index 0000000..4fda15c
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/bootstrap.test
@@ -0,0 +1,543 @@
+<?php
+
+class BootstrapIPAddressTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'IP address and HTTP_HOST test',
+ 'description' => 'Get the IP address from the current visitor from the server variables, check hostname validation.',
+ 'group' => 'Bootstrap'
+ );
+ }
+
+ function setUp() {
+ $this->oldserver = $_SERVER;
+
+ $this->remote_ip = '127.0.0.1';
+ $this->proxy_ip = '127.0.0.2';
+ $this->proxy2_ip = '127.0.0.3';
+ $this->forwarded_ip = '127.0.0.4';
+ $this->cluster_ip = '127.0.0.5';
+ $this->untrusted_ip = '0.0.0.0';
+
+ drupal_static_reset('ip_address');
+
+ $_SERVER['REMOTE_ADDR'] = $this->remote_ip;
+ unset($_SERVER['HTTP_X_FORWARDED_FOR']);
+ unset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']);
+
+ parent::setUp();
+ }
+
+ function tearDown() {
+ $_SERVER = $this->oldserver;
+ drupal_static_reset('ip_address');
+ parent::tearDown();
+ }
+
+ /**
+ * test IP Address and hostname
+ */
+ function testIPAddressHost() {
+ // Test the normal IP address.
+ $this->assertTrue(
+ ip_address() == $this->remote_ip,
+ 'Got remote IP address.'
+ );
+
+ // Proxy forwarding on but no proxy addresses defined.
+ variable_set('reverse_proxy', 1);
+ $this->assertTrue(
+ ip_address() == $this->remote_ip,
+ 'Proxy forwarding without trusted proxies got remote IP address.'
+ );
+
+ // Proxy forwarding on and proxy address not trusted.
+ variable_set('reverse_proxy_addresses', array($this->proxy_ip, $this->proxy2_ip));
+ drupal_static_reset('ip_address');
+ $_SERVER['REMOTE_ADDR'] = $this->untrusted_ip;
+ $this->assertTrue(
+ ip_address() == $this->untrusted_ip,
+ 'Proxy forwarding with untrusted proxy got remote IP address.'
+ );
+
+ // Proxy forwarding on and proxy address trusted.
+ $_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
+ $_SERVER['HTTP_X_FORWARDED_FOR'] = $this->forwarded_ip;
+ drupal_static_reset('ip_address');
+ $this->assertTrue(
+ ip_address() == $this->forwarded_ip,
+ 'Proxy forwarding with trusted proxy got forwarded IP address.'
+ );
+
+ // Multi-tier architecture with comma separated values in header.
+ $_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
+ $_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip));
+ drupal_static_reset('ip_address');
+ $this->assertTrue(
+ ip_address() == $this->forwarded_ip,
+ 'Proxy forwarding with trusted 2-tier proxy got forwarded IP address.'
+ );
+
+ // Custom client-IP header.
+ variable_set('reverse_proxy_header', 'HTTP_X_CLUSTER_CLIENT_IP');
+ $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] = $this->cluster_ip;
+ drupal_static_reset('ip_address');
+ $this->assertTrue(
+ ip_address() == $this->cluster_ip,
+ 'Cluster environment got cluster client IP.'
+ );
+
+ // Verifies that drupal_valid_http_host() prevents invalid characters.
+ $this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), 'HTTP_HOST with / is invalid');
+ $this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
+ $this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with &lt; is invalid');
+ $this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
+ // IPv6 loopback address
+ $this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid');
+ }
+}
+
+class BootstrapPageCacheTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Page cache test',
+ 'description' => 'Enable the page cache and test it with various HTTP requests.',
+ 'group' => 'Bootstrap'
+ );
+ }
+
+ function setUp() {
+ parent::setUp('system_test');
+ }
+
+ /**
+ * Test support for requests containing If-Modified-Since and If-None-Match headers.
+ */
+ function testConditionalRequests() {
+ variable_set('cache', 1);
+
+ // Fill the cache.
+ $this->drupalGet('');
+
+ $this->drupalHead('');
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+ $etag = $this->drupalGetHeader('ETag');
+ $last_modified = $this->drupalGetHeader('Last-Modified');
+
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
+ $this->assertResponse(304, 'Conditional request returned 304 Not Modified.');
+
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag));
+ $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
+
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag));
+ $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
+
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified));
+ $this->assertResponse(200, 'Conditional request without If-None-Match returned 200 OK.');
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC1123, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag));
+ $this->assertResponse(200, 'Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.');
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+
+ $user = $this->drupalCreateUser();
+ $this->drupalLogin($user);
+ $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
+ $this->assertResponse(200, 'Conditional request returned 200 OK for authenticated user.');
+ $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Absense of Page was not cached.');
+ }
+
+ /**
+ * Test cache headers.
+ */
+ function testPageCache() {
+ variable_set('cache', 1);
+
+ // Fill the cache.
+ $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
+ $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
+
+ // Check cache.
+ $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+ $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary: Cookie header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
+
+ // Check replacing default headers.
+ $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT')));
+ $this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.');
+ $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Vary', 'value' => 'User-Agent')));
+ $this->assertEqual($this->drupalGetHeader('Vary'), 'User-Agent,Accept-Encoding', 'Default header was replaced.');
+
+ // Check that authenticated users bypass the cache.
+ $user = $this->drupalCreateUser();
+ $this->drupalLogin($user);
+ $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
+ $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.');
+ $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
+ $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', 'Cache-Control header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
+
+ }
+
+ /**
+ * Test page compression.
+ *
+ * The test should pass even if zlib.output_compression is enabled in php.ini,
+ * .htaccess or similar, or if compression is done outside PHP, e.g. by the
+ * mod_deflate Apache module.
+ */
+ function testPageCompression() {
+ variable_set('cache', 1);
+
+ // Fill the cache and verify that output is compressed.
+ $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
+ $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
+ $this->assertRaw('</html>', 'Page was gzip compressed.');
+
+ // Verify that cached output is compressed.
+ $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+ $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', 'A Content-Encoding header was sent.');
+ $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
+ $this->assertRaw('</html>', 'Page was gzip compressed.');
+
+ // Verify that a client without compression support gets an uncompressed page.
+ $this->drupalGet('');
+ $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
+ $this->assertFalse($this->drupalGetHeader('Content-Encoding'), 'A Content-Encoding header was not sent.');
+ $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.');
+ $this->assertRaw('</html>', 'Page was not compressed.');
+
+ // Disable compression mode.
+ variable_set('page_compression', FALSE);
+
+ // Verify if cached page is still available for a client with compression support.
+ $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+ $this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
+ $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support enabled).');
+
+ // Verify if cached page is still available for a client without compression support.
+ $this->drupalGet('');
+ $this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support disabled).');
+ }
+}
+
+class BootstrapVariableTestCase extends DrupalWebTestCase {
+
+ function setUp() {
+ parent::setUp('system_test');
+ }
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Variable test',
+ 'description' => 'Make sure the variable system functions correctly.',
+ 'group' => 'Bootstrap'
+ );
+ }
+
+ /**
+ * testVariable
+ */
+ function testVariable() {
+ // Setting and retrieving values.
+ $variable = $this->randomName();
+ variable_set('simpletest_bootstrap_variable_test', $variable);
+ $this->assertIdentical($variable, variable_get('simpletest_bootstrap_variable_test'), 'Setting and retrieving values');
+
+ // Make sure the variable persists across multiple requests.
+ $this->drupalGet('system-test/variable-get');
+ $this->assertText($variable, 'Variable persists across multiple requests');
+
+ // Deleting variables.
+ $default_value = $this->randomName();
+ variable_del('simpletest_bootstrap_variable_test');
+ $variable = variable_get('simpletest_bootstrap_variable_test', $default_value);
+ $this->assertIdentical($variable, $default_value, 'Deleting variables');
+ }
+
+ /**
+ * Makes sure that the default variable parameter is passed through okay.
+ */
+ function testVariableDefaults() {
+ // Tests passing nothing through to the default.
+ $this->assertIdentical(NULL, variable_get('simpletest_bootstrap_variable_test'), 'Variables are correctly defaulting to NULL.');
+
+ // Tests passing 5 to the default parameter.
+ $this->assertIdentical(5, variable_get('simpletest_bootstrap_variable_test', 5), 'The default variable parameter is passed through correctly.');
+ }
+
+}
+
+/**
+ * Test hook_boot() and hook_exit().
+ */
+class HookBootExitTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Boot and exit hook invocation',
+ 'description' => 'Test that hook_boot() and hook_exit() are called correctly.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('system_test', 'dblog');
+ }
+
+ /**
+ * Test calling of hook_boot() and hook_exit().
+ */
+ function testHookBootExit() {
+ // Test with cache disabled. Boot and exit should always fire.
+ variable_set('cache', 0);
+ $this->drupalGet('');
+ $calls = 1;
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with disabled cache.'));
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with disabled cache.'));
+
+ // Test with normal cache. Boot and exit should be called.
+ variable_set('cache', 1);
+ $this->drupalGet('');
+ $calls++;
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.'));
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with normal cache.'));
+
+ // Boot and exit should not fire since the page is cached.
+ variable_set('page_cache_invoke_hooks', FALSE);
+ $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
+ $this->drupalGet('');
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot not called with aggressive cache and a cached page.'));
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit not called with aggressive cache and a cached page.'));
+
+ // Test with page cache cleared, boot and exit should be called.
+ $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
+ $this->drupalGet('');
+ $calls++;
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with aggressive cache and no cached page.'));
+ $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with aggressive cache and no cached page.'));
+ }
+}
+
+/**
+ * Test drupal_get_filename()'s availability.
+ */
+class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Get filename test',
+ 'description' => 'Test that drupal_get_filename() works correctly when the file is not found in the database.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ /**
+ * Test that drupal_get_filename() works correctly when the file is not found in the database.
+ */
+ function testDrupalGetFilename() {
+ // Reset the static cache so we can test the "db is not active" code of
+ // drupal_get_filename().
+ drupal_static_reset('drupal_get_filename');
+
+ // Retrieving the location of a module.
+ $this->assertIdentical(drupal_get_filename('module', 'php'), 'modules/php/php.module', t('Retrieve module location.'));
+
+ // Retrieving the location of a theme.
+ $this->assertIdentical(drupal_get_filename('theme', 'stark'), 'themes/stark/stark.info', t('Retrieve theme location.'));
+
+ // Retrieving the location of a theme engine.
+ $this->assertIdentical(drupal_get_filename('theme_engine', 'phptemplate'), 'themes/engines/phptemplate/phptemplate.engine', t('Retrieve theme engine location.'));
+
+ // Retrieving the location of a profile. Profiles are a special case with
+ // a fixed location and naming.
+ $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'profiles/standard/standard.profile', t('Retrieve install profile location.'));
+
+ // When a file is not found in the database cache, drupal_get_filename()
+ // searches several locations on the filesystem, including the DRUPAL_ROOT
+ // directory. We use the '.script' extension below because this is a
+ // non-existent filetype that will definitely not exist in the database.
+ // Since there is already a scripts directory, drupal_get_filename() will
+ // automatically check there for 'script' files, just as it does for (e.g.)
+ // 'module' files in modules.
+ $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.'));
+ }
+}
+
+class BootstrapTimerTestCase extends DrupalUnitTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Timer test',
+ 'description' => 'Test that timer_read() works both when a timer is running and when a timer is stopped.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ /**
+ * Test timer_read() to ensure it properly accumulates time when the timer
+ * started and stopped multiple times.
+ * @return
+ */
+ function testTimer() {
+ timer_start('test');
+ sleep(1);
+ $this->assertTrue(timer_read('test') >= 1000, 'Timer measured 1 second of sleeping while running.');
+ sleep(1);
+ timer_stop('test');
+ $this->assertTrue(timer_read('test') >= 2000, 'Timer measured 2 seconds of sleeping after being stopped.');
+ timer_start('test');
+ sleep(1);
+ $this->assertTrue(timer_read('test') >= 3000, 'Timer measured 3 seconds of sleeping after being restarted.');
+ sleep(1);
+ $timer = timer_stop('test');
+ $this->assertTrue(timer_read('test') >= 4000, 'Timer measured 4 seconds of sleeping after being stopped for a second time.');
+ $this->assertEqual($timer['count'], 2, 'Timer counted 2 instances of being started.');
+ }
+}
+
+/**
+ * Test that resetting static variables works.
+ */
+class BootstrapResettableStaticTestCase extends DrupalUnitTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Resettable static variables test',
+ 'description' => 'Test that drupal_static() and drupal_static_reset() work.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ /**
+ * Test that a variable reference returned by drupal_static() gets reset when
+ * drupal_static_reset() is called.
+ */
+ function testDrupalStatic() {
+ $name = __CLASS__ . '_' . __METHOD__;
+ $var = &drupal_static($name, 'foo');
+ $this->assertEqual($var, 'foo', 'Variable returned by drupal_static() was set to its default.');
+
+ // Call the specific reset and the global reset each twice to ensure that
+ // multiple resets can be issued without odd side effects.
+ $var = 'bar';
+ drupal_static_reset($name);
+ $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of name-specific reset.');
+ $var = 'bar';
+ drupal_static_reset($name);
+ $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of name-specific reset.');
+ $var = 'bar';
+ drupal_static_reset();
+ $this->assertEqual($var, 'foo', 'Variable was reset after first invocation of global reset.');
+ $var = 'bar';
+ drupal_static_reset();
+ $this->assertEqual($var, 'foo', 'Variable was reset after second invocation of global reset.');
+ }
+}
+
+/**
+ * Test miscellaneous functions in bootstrap.inc.
+ */
+class BootstrapMiscTestCase extends DrupalUnitTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Miscellaneous bootstrap unit tests',
+ 'description' => 'Test miscellaneous functions in bootstrap.inc.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ /**
+ * Test miscellaneous functions in bootstrap.inc.
+ */
+ function testMisc() {
+ // Test drupal_array_merge_deep().
+ $link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => 'X', 'class' => array('a', 'b')), 'language' => 'en');
+ $link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('c', 'd')), 'html' => TRUE);
+ $expected = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('a', 'b', 'c', 'd')), 'language' => 'en', 'html' => TRUE);
+ $this->assertIdentical(drupal_array_merge_deep($link_options_1, $link_options_2), $expected, 'drupal_array_merge_deep() returned a properly merged array.');
+ }
+
+ /**
+ * Tests that the drupal_check_memory_limit() function works as expected.
+ */
+ function testCheckMemoryLimit() {
+ $memory_limit = ini_get('memory_limit');
+ // Test that a very reasonable amount of memory is available.
+ $this->assertTrue(drupal_check_memory_limit('30MB'), '30MB of memory tested available.');
+
+ // Get the available memory and multiply it by two to make it unreasonably
+ // high.
+ $twice_avail_memory = ($memory_limit * 2) . 'MB';
+
+ // The function should always return true if the memory limit is set to -1.
+ $this->assertTrue(drupal_check_memory_limit($twice_avail_memory, -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied');
+
+ // Test that even though we have 30MB of memory available - the function
+ // returns FALSE when given an upper limit for how much memory can be used.
+ $this->assertFalse(drupal_check_memory_limit('30MB', '16MB'), 'drupal_check_memory_limit() returns FALSE with a 16MB upper limit on a 30MB requirement.');
+
+ // Test that an equal amount of memory to the amount requested returns TRUE.
+ $this->assertTrue(drupal_check_memory_limit('30MB', '30MB'), 'drupal_check_memory_limit() returns TRUE when requesting 30MB on a 30MB requirement.');
+ }
+}
+
+/**
+ * Tests for overriding server variables via the API.
+ */
+class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Overriding server variables',
+ 'description' => 'Test that drupal_override_server_variables() works correctly.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ /**
+ * Test providing a direct URL to to drupal_override_server_variables().
+ */
+ function testDrupalOverrideServerVariablesProvidedURL() {
+ $tests = array(
+ 'http://example.com' => array(
+ 'HTTP_HOST' => 'example.com',
+ 'SCRIPT_NAME' => isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL,
+ ),
+ 'http://example.com/index.php' => array(
+ 'HTTP_HOST' => 'example.com',
+ 'SCRIPT_NAME' => '/index.php',
+ ),
+ 'http://example.com/subdirectory/index.php' => array(
+ 'HTTP_HOST' => 'example.com',
+ 'SCRIPT_NAME' => '/subdirectory/index.php',
+ ),
+ );
+ foreach ($tests as $url => $expected_server_values) {
+ // Remember the original value of $_SERVER, since the function call below
+ // will modify it.
+ $original_server = $_SERVER;
+ // Call drupal_override_server_variables() and ensure that all expected
+ // $_SERVER variables were modified correctly.
+ drupal_override_server_variables(array('url' => $url));
+ foreach ($expected_server_values as $key => $value) {
+ $this->assertIdentical($_SERVER[$key], $value);
+ }
+ // Restore the original value of $_SERVER.
+ $_SERVER = $original_server;
+ }
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/cache.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/cache.test
new file mode 100644
index 0000000..b42de36
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/cache.test
@@ -0,0 +1,437 @@
+<?php
+
+class CacheTestCase extends DrupalWebTestCase {
+ protected $default_bin = 'cache';
+ protected $default_cid = 'test_temporary';
+ protected $default_value = 'CacheTest';
+
+ /**
+ * Check whether or not a cache entry exists.
+ *
+ * @param $cid
+ * The cache id.
+ * @param $var
+ * The variable the cache should contain.
+ * @param $bin
+ * The bin the cache item was stored in.
+ * @return
+ * TRUE on pass, FALSE on fail.
+ */
+ protected function checkCacheExists($cid, $var, $bin = NULL) {
+ if ($bin == NULL) {
+ $bin = $this->default_bin;
+ }
+
+ $cache = cache_get($cid, $bin);
+
+ return isset($cache->data) && $cache->data == $var;
+ }
+
+ /**
+ * Assert or a cache entry exists.
+ *
+ * @param $message
+ * Message to display.
+ * @param $var
+ * The variable the cache should contain.
+ * @param $cid
+ * The cache id.
+ * @param $bin
+ * The bin the cache item was stored in.
+ */
+ protected function assertCacheExists($message, $var = NULL, $cid = NULL, $bin = NULL) {
+ if ($bin == NULL) {
+ $bin = $this->default_bin;
+ }
+ if ($cid == NULL) {
+ $cid = $this->default_cid;
+ }
+ if ($var == NULL) {
+ $var = $this->default_value;
+ }
+
+ $this->assertTrue($this->checkCacheExists($cid, $var, $bin), $message);
+ }
+
+ /**
+ * Assert or a cache entry has been removed.
+ *
+ * @param $message
+ * Message to display.
+ * @param $cid
+ * The cache id.
+ * @param $bin
+ * The bin the cache item was stored in.
+ */
+ function assertCacheRemoved($message, $cid = NULL, $bin = NULL) {
+ if ($bin == NULL) {
+ $bin = $this->default_bin;
+ }
+ if ($cid == NULL) {
+ $cid = $this->default_cid;
+ }
+
+ $cache = cache_get($cid, $bin);
+ $this->assertFalse($cache, $message);
+ }
+
+ /**
+ * Perform the general wipe.
+ * @param $bin
+ * The bin to perform the wipe on.
+ */
+ protected function generalWipe($bin = NULL) {
+ if ($bin == NULL) {
+ $bin = $this->default_bin;
+ }
+
+ cache_clear_all(NULL, $bin);
+ }
+
+ /**
+ * Setup the lifetime settings for caching.
+ *
+ * @param $time
+ * The time in seconds the cache should minimal live.
+ */
+ protected function setupLifetime($time) {
+ variable_set('cache_lifetime', $time);
+ variable_set('cache_flush', 0);
+ }
+}
+
+class CacheSavingCase extends CacheTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Cache saving test',
+ 'description' => 'Check our variables are saved and restored the right way.',
+ 'group' => 'Cache'
+ );
+ }
+
+ /**
+ * Test the saving and restoring of a string.
+ */
+ function testString() {
+ $this->checkVariable($this->randomName(100));
+ }
+
+ /**
+ * Test the saving and restoring of an integer.
+ */
+ function testInteger() {
+ $this->checkVariable(100);
+ }
+
+ /**
+ * Test the saving and restoring of a double.
+ */
+ function testDouble() {
+ $this->checkVariable(1.29);
+ }
+
+ /**
+ * Test the saving and restoring of an array.
+ */
+ function testArray() {
+ $this->checkVariable(array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6')));
+ }
+
+ /**
+ * Test the saving and restoring of an object.
+ */
+ function testObject() {
+ $test_object = new stdClass();
+ $test_object->test1 = $this->randomName(100);
+ $test_object->test2 = 100;
+ $test_object->test3 = array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6'));
+
+ cache_set('test_object', $test_object, 'cache');
+ $cache = cache_get('test_object', 'cache');
+ $this->assertTrue(isset($cache->data) && $cache->data == $test_object, 'Object is saved and restored properly.');
+ }
+
+ /**
+ * Check or a variable is stored and restored properly.
+ */
+ function checkVariable($var) {
+ cache_set('test_var', $var, 'cache');
+ $cache = cache_get('test_var', 'cache');
+ $this->assertTrue(isset($cache->data) && $cache->data === $var, format_string('@type is saved and restored properly.', array('@type' => ucfirst(gettype($var)))));
+ }
+
+ /**
+ * Test no empty cids are written in cache table.
+ */
+ function testNoEmptyCids() {
+ $this->drupalGet('user/register');
+ $this->assertFalse(cache_get(''), 'No cache entry is written with an empty cid.');
+ }
+}
+
+/**
+ * Test cache_get_multiple().
+ */
+class CacheGetMultipleUnitTest extends CacheTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Fetching multiple cache items',
+ 'description' => 'Confirm that multiple records are fetched correctly.',
+ 'group' => 'Cache',
+ );
+ }
+
+ function setUp() {
+ $this->default_bin = 'cache_page';
+ parent::setUp();
+ }
+
+ /**
+ * Test cache_get_multiple().
+ */
+ function testCacheMultiple() {
+ $item1 = $this->randomName(10);
+ $item2 = $this->randomName(10);
+ cache_set('item1', $item1, $this->default_bin);
+ cache_set('item2', $item2, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('item1', $item1), 'Item 1 is cached.');
+ $this->assertTrue($this->checkCacheExists('item2', $item2), 'Item 2 is cached.');
+
+ // Fetch both records from the database with cache_get_multiple().
+ $item_ids = array('item1', 'item2');
+ $items = cache_get_multiple($item_ids, $this->default_bin);
+ $this->assertEqual($items['item1']->data, $item1, 'Item was returned from cache successfully.');
+ $this->assertEqual($items['item2']->data, $item2, 'Item was returned from cache successfully.');
+
+ // Remove one item from the cache.
+ cache_clear_all('item2', $this->default_bin);
+
+ // Confirm that only one item is returned by cache_get_multiple().
+ $item_ids = array('item1', 'item2');
+ $items = cache_get_multiple($item_ids, $this->default_bin);
+ $this->assertEqual($items['item1']->data, $item1, 'Item was returned from cache successfully.');
+ $this->assertFalse(isset($items['item2']), 'Item was not returned from the cache.');
+ $this->assertTrue(count($items) == 1, 'Only valid cache entries returned.');
+ }
+}
+
+/**
+ * Test cache clearing methods.
+ */
+class CacheClearCase extends CacheTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Cache clear test',
+ 'description' => 'Check our clearing is done the proper way.',
+ 'group' => 'Cache'
+ );
+ }
+
+ function setUp() {
+ $this->default_bin = 'cache_page';
+ $this->default_value = $this->randomName(10);
+
+ parent::setUp();
+ }
+
+ /**
+ * Test clearing using a cid.
+ */
+ function testClearCid() {
+ cache_set('test_cid_clear', $this->default_value, $this->default_bin);
+
+ $this->assertCacheExists(t('Cache was set for clearing cid.'), $this->default_value, 'test_cid_clear');
+ cache_clear_all('test_cid_clear', $this->default_bin);
+
+ $this->assertCacheRemoved(t('Cache was removed after clearing cid.'), 'test_cid_clear');
+
+ cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches were created for checking cid "*" with wildcard false.');
+ cache_clear_all('*', $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches still exists after clearing cid "*" with wildcard false.');
+ }
+
+ /**
+ * Test clearing using wildcard.
+ */
+ function testClearWildcard() {
+ cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches were created for checking cid "*" with wildcard true.');
+ cache_clear_all('*', $this->default_bin, TRUE);
+ $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ || $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches removed after clearing cid "*" with wildcard true.');
+
+ cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches were created for checking cid substring with wildcard true.');
+ cache_clear_all('test_', $this->default_bin, TRUE);
+ $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ || $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two caches removed after clearing cid substring with wildcard true.');
+ }
+
+ /**
+ * Test clearing using an array.
+ */
+ function testClearArray() {
+ // Create three cache entries.
+ cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear3', $this->default_value, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear3', $this->default_value),
+ 'Three cache entries were created.');
+
+ // Clear two entries using an array.
+ cache_clear_all(array('test_cid_clear1', 'test_cid_clear2'), $this->default_bin);
+ $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ || $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two cache entries removed after clearing with an array.');
+
+ $this->assertTrue($this->checkCacheExists('test_cid_clear3', $this->default_value),
+ 'Entry was not cleared from the cache');
+
+ // Set the cache clear threshold to 2 to confirm that the full bin is cleared
+ // when the threshold is exceeded.
+ variable_set('cache_clear_threshold', 2);
+ cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
+ cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
+ $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ && $this->checkCacheExists('test_cid_clear2', $this->default_value),
+ 'Two cache entries were created.');
+ cache_clear_all(array('test_cid_clear1', 'test_cid_clear2', 'test_cid_clear3'), $this->default_bin);
+ $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
+ || $this->checkCacheExists('test_cid_clear2', $this->default_value)
+ || $this->checkCacheExists('test_cid_clear3', $this->default_value),
+ 'All cache entries removed when the array exceeded the cache clear threshold.');
+ }
+
+ /**
+ * Test drupal_flush_all_caches().
+ */
+ function testFlushAllCaches() {
+ // Create cache entries for each flushed cache bin.
+ $bins = array('cache', 'cache_filter', 'cache_page', 'cache_boostrap', 'cache_path');
+ $bins = array_merge(module_invoke_all('flush_caches'), $bins);
+ foreach ($bins as $id => $bin) {
+ $id = 'test_cid_clear' . $id;
+ cache_set($id, $this->default_value, $bin);
+ }
+
+ // Remove all caches then make sure that they are cleared.
+ drupal_flush_all_caches();
+
+ foreach ($bins as $id => $bin) {
+ $id = 'test_cid_clear' . $id;
+ $this->assertFalse($this->checkCacheExists($id, $this->default_value, $bin), format_string('All cache entries removed from @bin.', array('@bin' => $bin)));
+ }
+ }
+
+ /**
+ * Test DrupalDatabaseCache::isValidBin().
+ */
+ function testIsValidBin() {
+ // Retrieve existing cache bins.
+ $valid_bins = array('cache', 'cache_filter', 'cache_page', 'cache_boostrap', 'cache_path');
+ $valid_bins = array_merge(module_invoke_all('flush_caches'), $valid_bins);
+ foreach ($valid_bins as $id => $bin) {
+ $cache = _cache_get_object($bin);
+ if ($cache instanceof DrupalDatabaseCache) {
+ $this->assertTrue($cache->isValidBin(), format_string('Cache bin @bin is valid.', array('@bin' => $bin)));
+ }
+ }
+
+ // Check for non-cache tables and invalid bins.
+ $invalid_bins = array('block', 'filter', 'missing_table', $this->randomName());
+ foreach ($invalid_bins as $id => $bin) {
+ $cache = _cache_get_object($bin);
+ if ($cache instanceof DrupalDatabaseCache) {
+ $this->assertFalse($cache->isValidBin(), format_string('Cache bin @bin is not valid.', array('@bin' => $bin)));
+ }
+ }
+ }
+
+ /**
+ * Test minimum cache lifetime.
+ */
+ function testMinimumCacheLifetime() {
+ // Set a minimum/maximum cache lifetime.
+ $this->setupLifetime(300);
+ // Login as a newly-created user.
+ $account = $this->drupalCreateUser(array());
+ $this->drupalLogin($account);
+
+ // Set two cache objects in different bins.
+ $data = $this->randomName(100);
+ cache_set($data, $data, 'cache', CACHE_TEMPORARY);
+ $cached = cache_get($data);
+ $this->assertTrue(isset($cached->data) && $cached->data === $data, 'Cached item retrieved.');
+ cache_set($data, $data, 'cache_page', CACHE_TEMPORARY);
+
+ // Expire temporary items in the 'page' bin.
+ cache_clear_all(NULL, 'cache_page');
+
+ // Since the database cache uses REQUEST_TIME, set the $_SESSION variable
+ // manually to force it to the current time.
+ $_SESSION['cache_expiration']['cache_page'] = time();
+
+ // Items in the default cache bin should not be expired.
+ $cached = cache_get($data);
+ $this->assertTrue(isset($cached->data) && $cached->data == $data, 'Cached item retrieved');
+
+ // Despite the minimum cache lifetime, the item in the 'page' bin should
+ // be invalidated for the current user.
+ $cached = cache_get($data, 'cache_page');
+ $this->assertFalse($cached, 'Cached item was invalidated');
+ }
+}
+
+/**
+ * Test cache_is_empty() function.
+ */
+class CacheIsEmptyCase extends CacheTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Cache emptiness test',
+ 'description' => 'Check if a cache bin is empty after performing clear operations.',
+ 'group' => 'Cache'
+ );
+ }
+
+ function setUp() {
+ $this->default_bin = 'cache_page';
+ $this->default_value = $this->randomName(10);
+
+ parent::setUp();
+ }
+
+ /**
+ * Test clearing using a cid.
+ */
+ function testIsEmpty() {
+ // Clear the cache bin.
+ cache_clear_all('*', $this->default_bin);
+ $this->assertTrue(cache_is_empty($this->default_bin), 'The cache bin is empty');
+ // Add some data to the cache bin.
+ cache_set($this->default_cid, $this->default_value, $this->default_bin);
+ $this->assertCacheExists(t('Cache was set.'), $this->default_value, $this->default_cid);
+ $this->assertFalse(cache_is_empty($this->default_bin), 'The cache bin is not empty');
+ // Remove the cached data.
+ cache_clear_all($this->default_cid, $this->default_bin);
+ $this->assertCacheRemoved(t('Cache was removed.'), $this->default_cid);
+ $this->assertTrue(cache_is_empty($this->default_bin), 'The cache bin is empty');
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/common.test b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common.test
new file mode 100644
index 0000000..44eecdc
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common.test
@@ -0,0 +1,2787 @@
+<?php
+
+/**
+ * @file
+ * Tests for common.inc functionality.
+ */
+
+/**
+ * Tests for URL generation functions.
+ */
+class DrupalAlterTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'drupal_alter() tests',
+ 'description' => 'Confirm that alteration of arguments passed to drupal_alter() works correctly.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('common_test');
+ }
+
+ function testDrupalAlter() {
+ // This test depends on Bartik, so make sure that it is always the current
+ // active theme.
+ global $theme, $base_theme_info;
+ $theme = 'bartik';
+ $base_theme_info = array();
+
+ $array = array('foo' => 'bar');
+ $entity = new stdClass();
+ $entity->foo = 'bar';
+
+ // Verify alteration of a single argument.
+ $array_copy = $array;
+ $array_expected = array('foo' => 'Drupal theme');
+ drupal_alter('drupal_alter', $array_copy);
+ $this->assertEqual($array_copy, $array_expected, 'Single array was altered.');
+
+ $entity_copy = clone $entity;
+ $entity_expected = clone $entity;
+ $entity_expected->foo = 'Drupal theme';
+ drupal_alter('drupal_alter', $entity_copy);
+ $this->assertEqual($entity_copy, $entity_expected, 'Single object was altered.');
+
+ // Verify alteration of multiple arguments.
+ $array_copy = $array;
+ $array_expected = array('foo' => 'Drupal theme');
+ $entity_copy = clone $entity;
+ $entity_expected = clone $entity;
+ $entity_expected->foo = 'Drupal theme';
+ $array2_copy = $array;
+ $array2_expected = array('foo' => 'Drupal theme');
+ drupal_alter('drupal_alter', $array_copy, $entity_copy, $array2_copy);
+ $this->assertEqual($array_copy, $array_expected, 'First argument to drupal_alter() was altered.');
+ $this->assertEqual($entity_copy, $entity_expected, 'Second argument to drupal_alter() was altered.');
+ $this->assertEqual($array2_copy, $array2_expected, 'Third argument to drupal_alter() was altered.');
+
+ // Verify alteration order when passing an array of types to drupal_alter().
+ // common_test_module_implements_alter() places 'block' implementation after
+ // other modules.
+ $array_copy = $array;
+ $array_expected = array('foo' => 'Drupal block theme');
+ drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy);
+ $this->assertEqual($array_copy, $array_expected, 'hook_TYPE_alter() implementations ran in correct order.');
+ }
+}
+
+/**
+ * Tests for URL generation functions.
+ *
+ * url() calls module_implements(), which may issue a db query, which requires
+ * inheriting from a web test case rather than a unit test case.
+ */
+class CommonURLUnitTest extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'URL generation tests',
+ 'description' => 'Confirm that url(), drupal_get_query_parameters(), drupal_http_build_query(), and l() work correctly with various input.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Confirm that invalid text given as $path is filtered.
+ */
+ function testLXSS() {
+ $text = $this->randomName();
+ $path = "<SCRIPT>alert('XSS')</SCRIPT>";
+ $link = l($text, $path);
+ $sanitized_path = check_url(url($path));
+ $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered', array('@path' => $path)));
+ }
+
+ /*
+ * Tests for active class in l() function.
+ */
+ function testLActiveClass() {
+ $link = l($this->randomName(), $_GET['q']);
+ $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active')));
+ }
+
+ /**
+ * Tests for custom class in l() function.
+ */
+ function testLCustomClass() {
+ $class = $this->randomName();
+ $link = l($this->randomName(), $_GET['q'], array('attributes' => array('class' => array($class))));
+ $this->assertTrue($this->hasClass($link, $class), format_string('Custom class @class is present on link when requested', array('@class' => $class)));
+ $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active')));
+ }
+
+ private function hasClass($link, $class) {
+ return preg_match('|class="([^\"\s]+\s+)*' . $class . '|', $link);
+ }
+
+ /**
+ * Test drupal_get_query_parameters().
+ */
+ function testDrupalGetQueryParameters() {
+ $original = array(
+ 'a' => 1,
+ 'b' => array(
+ 'd' => 4,
+ 'e' => array(
+ 'f' => 5,
+ ),
+ ),
+ 'c' => 3,
+ 'q' => 'foo/bar',
+ );
+
+ // Default arguments.
+ $result = $_GET;
+ unset($result['q']);
+ $this->assertEqual(drupal_get_query_parameters(), $result, "\$_GET['q'] was removed.");
+
+ // Default exclusion.
+ $result = $original;
+ unset($result['q']);
+ $this->assertEqual(drupal_get_query_parameters($original), $result, "'q' was removed.");
+
+ // First-level exclusion.
+ $result = $original;
+ unset($result['b']);
+ $this->assertEqual(drupal_get_query_parameters($original, array('b')), $result, "'b' was removed.");
+
+ // Second-level exclusion.
+ $result = $original;
+ unset($result['b']['d']);
+ $this->assertEqual(drupal_get_query_parameters($original, array('b[d]')), $result, "'b[d]' was removed.");
+
+ // Third-level exclusion.
+ $result = $original;
+ unset($result['b']['e']['f']);
+ $this->assertEqual(drupal_get_query_parameters($original, array('b[e][f]')), $result, "'b[e][f]' was removed.");
+
+ // Multiple exclusions.
+ $result = $original;
+ unset($result['a'], $result['b']['e'], $result['c']);
+ $this->assertEqual(drupal_get_query_parameters($original, array('a', 'b[e]', 'c')), $result, "'a', 'b[e]', 'c' were removed.");
+ }
+
+ /**
+ * Test drupal_http_build_query().
+ */
+ function testDrupalHttpBuildQuery() {
+ $this->assertEqual(drupal_http_build_query(array('a' => ' &#//+%20@۞')), 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.');
+ $this->assertEqual(drupal_http_build_query(array(' &#//+%20@۞' => 'a')), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.');
+ $this->assertEqual(drupal_http_build_query(array('a' => '1', 'b' => '2', 'c' => '3')), 'a=1&b=2&c=3', 'Multiple values were properly concatenated.');
+ $this->assertEqual(drupal_http_build_query(array('a' => array('b' => '2', 'c' => '3'), 'd' => 'foo')), 'a[b]=2&a[c]=3&d=foo', 'Nested array was properly encoded.');
+ }
+
+ /**
+ * Test drupal_parse_url().
+ */
+ function testDrupalParseUrl() {
+ // Relative URL.
+ $url = 'foo/bar?foo=bar&bar=baz&baz#foo';
+ $result = array(
+ 'path' => 'foo/bar',
+ 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
+ 'fragment' => 'foo',
+ );
+ $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL parsed correctly.');
+
+ // Relative URL that is known to confuse parse_url().
+ $url = 'foo/bar:1';
+ $result = array(
+ 'path' => 'foo/bar:1',
+ 'query' => array(),
+ 'fragment' => '',
+ );
+ $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL parsed correctly.');
+
+ // Absolute URL.
+ $url = '/foo/bar?foo=bar&bar=baz&baz#foo';
+ $result = array(
+ 'path' => '/foo/bar',
+ 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
+ 'fragment' => 'foo',
+ );
+ $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL parsed correctly.');
+
+ // External URL testing.
+ $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
+
+ // Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
+ $this->assertTrue(url_is_external($url), 'Correctly identified an external URL.');
+
+ // Test the parsing of absolute URLs.
+ $result = array(
+ 'path' => 'http://drupal.org/foo/bar',
+ 'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
+ 'fragment' => 'foo',
+ );
+ $this->assertEqual(drupal_parse_url($url), $result, 'External URL parsed correctly.');
+
+ // Verify proper parsing of URLs when clean URLs are disabled.
+ $result = array(
+ 'path' => 'foo/bar',
+ 'query' => array('bar' => 'baz'),
+ 'fragment' => 'foo',
+ );
+ // Non-clean URLs #1: Absolute URL generated by url().
+ $url = $GLOBALS['base_url'] . '/?q=foo/bar&bar=baz#foo';
+ $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL with clean URLs disabled parsed correctly.');
+
+ // Non-clean URLs #2: Relative URL generated by url().
+ $url = '?q=foo/bar&bar=baz#foo';
+ $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL with clean URLs disabled parsed correctly.');
+
+ // Non-clean URLs #3: URL generated by url() on non-Apache webserver.
+ $url = 'index.php?q=foo/bar&bar=baz#foo';
+ $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL on non-Apache webserver with clean URLs disabled parsed correctly.');
+
+ // Test that drupal_parse_url() does not allow spoofing a URL to force a malicious redirect.
+ $parts = drupal_parse_url('forged:http://cwe.mitre.org/data/definitions/601.html');
+ $this->assertFalse(valid_url($parts['path'], TRUE), 'drupal_parse_url() correctly parsed a forged URL.');
+ }
+
+ /**
+ * Test url() with/without query, with/without fragment, absolute on/off and
+ * assert all that works when clean URLs are on and off.
+ */
+ function testUrl() {
+ global $base_url;
+
+ foreach (array(FALSE, TRUE) as $absolute) {
+ // Get the expected start of the path string.
+ $base = $absolute ? $base_url . '/' : base_path();
+ $absolute_string = $absolute ? 'absolute' : NULL;
+
+ // Disable Clean URLs.
+ $GLOBALS['conf']['clean_url'] = 0;
+
+ $url = $base . '?q=node/123';
+ $result = url('node/123', array('absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123#foo';
+ $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123&foo';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123&foo=bar&bar=baz';
+ $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123&foo#bar';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123&foo#0';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '0', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . '?q=node/123&foo';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base;
+ $result = url('<front>', array('absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ // Enable Clean URLs.
+ $GLOBALS['conf']['clean_url'] = 1;
+
+ $url = $base . 'node/123';
+ $result = url('node/123', array('absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . 'node/123#foo';
+ $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . 'node/123?foo';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . 'node/123?foo=bar&bar=baz';
+ $result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base . 'node/123?foo#bar';
+ $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+
+ $url = $base;
+ $result = url('<front>', array('absolute' => $absolute));
+ $this->assertEqual($url, $result, "$url == $result");
+ }
+ }
+
+ /**
+ * Test external URL handling.
+ */
+ function testExternalUrls() {
+ $test_url = 'http://drupal.org/';
+
+ // Verify external URL can contain a fragment.
+ $url = $test_url . '#drupal';
+ $result = url($url);
+ $this->assertEqual($url, $result, 'External URL with fragment works without a fragment in $options.');
+
+ // Verify fragment can be overidden in an external URL.
+ $url = $test_url . '#drupal';
+ $fragment = $this->randomName(10);
+ $result = url($url, array('fragment' => $fragment));
+ $this->assertEqual($test_url . '#' . $fragment, $result, 'External URL fragment is overidden with a custom fragment in $options.');
+
+ // Verify external URL can contain a query string.
+ $url = $test_url . '?drupal=awesome';
+ $result = url($url);
+ $this->assertEqual($url, $result, 'External URL with query string works without a query string in $options.');
+
+ // Verify external URL can be extended with a query string.
+ $url = $test_url;
+ $query = array($this->randomName(5) => $this->randomName(5));
+ $result = url($url, array('query' => $query));
+ $this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.');
+
+ // Verify query string can be extended in an external URL.
+ $url = $test_url . '?drupal=awesome';
+ $query = array($this->randomName(5) => $this->randomName(5));
+ $result = url($url, array('query' => $query));
+ $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, 'External URL query string can be extended with a custom query string in $options.');
+ }
+}
+
+/**
+ * Tests for check_plain(), filter_xss(), format_string(), and check_url().
+ */
+class CommonXssUnitTest extends DrupalUnitTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'String filtering tests',
+ 'description' => 'Confirm that check_plain(), filter_xss(), format_string() and check_url() work correctly, including invalid multi-byte sequences.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Check that invalid multi-byte sequences are rejected.
+ */
+ function testInvalidMultiByte() {
+ // Ignore PHP 5.3+ invalid multibyte sequence warning.
+ $text = @check_plain("Foo\xC0barbaz");
+ $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"');
+ // Ignore PHP 5.3+ invalid multibyte sequence warning.
+ $text = @check_plain("\xc2\"");
+ $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "\xc2\""');
+ $text = check_plain("Fooÿñ");
+ $this->assertEqual($text, "Fooÿñ", 'check_plain() accepts valid sequence "Fooÿñ"');
+ $text = filter_xss("Foo\xC0barbaz");
+ $this->assertEqual($text, '', 'filter_xss() rejects invalid sequence "Foo\xC0barbaz"');
+ $text = filter_xss("Fooÿñ");
+ $this->assertEqual($text, "Fooÿñ", 'filter_xss() accepts valid sequence Fooÿñ');
+ }
+
+ /**
+ * Check that special characters are escaped.
+ */
+ function testEscaping() {
+ $text = check_plain("<script>");
+ $this->assertEqual($text, '&lt;script&gt;', 'check_plain() escapes &lt;script&gt;');
+ $text = check_plain('<>&"\'');
+ $this->assertEqual($text, '&lt;&gt;&amp;&quot;&#039;', 'check_plain() escapes reserved HTML characters.');
+ }
+
+ /**
+ * Test t() and format_string() replacement functionality.
+ */
+ function testFormatStringAndT() {
+ foreach (array('format_string', 't') as $function) {
+ $text = $function('Simple text');
+ $this->assertEqual($text, 'Simple text', $function . ' leaves simple text alone.');
+ $text = $function('Escaped text: @value', array('@value' => '<script>'));
+ $this->assertEqual($text, 'Escaped text: &lt;script&gt;', $function . ' replaces and escapes string.');
+ $text = $function('Placeholder text: %value', array('%value' => '<script>'));
+ $this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', $function . ' replaces, escapes and themes string.');
+ $text = $function('Verbatim text: !value', array('!value' => '<script>'));
+ $this->assertEqual($text, 'Verbatim text: <script>', $function . ' replaces verbatim string as-is.');
+ }
+ }
+
+ /**
+ * Check that harmful protocols are stripped.
+ */
+ function testBadProtocolStripping() {
+ // Ensure that check_url() strips out harmful protocols, and encodes for
+ // HTML. Ensure drupal_strip_dangerous_protocols() can be used to return a
+ // plain-text string stripped of harmful protocols.
+ $url = 'javascript:http://www.example.com/?x=1&y=2';
+ $expected_plain = 'http://www.example.com/?x=1&y=2';
+ $expected_html = 'http://www.example.com/?x=1&amp;y=2';
+ $this->assertIdentical(check_url($url), $expected_html, 'check_url() filters a URL and encodes it for HTML.');
+ $this->assertIdentical(drupal_strip_dangerous_protocols($url), $expected_plain, 'drupal_strip_dangerous_protocols() filters a URL and returns plain text.');
+ }
+}
+
+/**
+ * Tests file size parsing and formatting functions.
+ */
+class CommonSizeTestCase extends DrupalUnitTestCase {
+ protected $exact_test_cases;
+ protected $rounded_test_cases;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Size parsing test',
+ 'description' => 'Parse a predefined amount of bytes and compare the output with the expected value.',
+ 'group' => 'System'
+ );
+ }
+
+ function setUp() {
+ $kb = DRUPAL_KILOBYTE;
+ $this->exact_test_cases = array(
+ '1 byte' => 1,
+ '1 KB' => $kb,
+ '1 MB' => $kb * $kb,
+ '1 GB' => $kb * $kb * $kb,
+ '1 TB' => $kb * $kb * $kb * $kb,
+ '1 PB' => $kb * $kb * $kb * $kb * $kb,
+ '1 EB' => $kb * $kb * $kb * $kb * $kb * $kb,
+ '1 ZB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb,
+ '1 YB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb * $kb,
+ );
+ $this->rounded_test_cases = array(
+ '2 bytes' => 2,
+ '1 MB' => ($kb * $kb) - 1, // rounded to 1 MB (not 1000 or 1024 kilobyte!)
+ round(3623651 / ($this->exact_test_cases['1 MB']), 2) . ' MB' => 3623651, // megabytes
+ round(67234178751368124 / ($this->exact_test_cases['1 PB']), 2) . ' PB' => 67234178751368124, // petabytes
+ round(235346823821125814962843827 / ($this->exact_test_cases['1 YB']), 2) . ' YB' => 235346823821125814962843827, // yottabytes
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Check that format_size() returns the expected string.
+ */
+ function testCommonFormatSize() {
+ foreach (array($this->exact_test_cases, $this->rounded_test_cases) as $test_cases) {
+ foreach ($test_cases as $expected => $input) {
+ $this->assertEqual(
+ ($result = format_size($input, NULL)),
+ $expected,
+ $expected . ' == ' . $result . ' (' . $input . ' bytes)'
+ );
+ }
+ }
+ }
+
+ /**
+ * Check that parse_size() returns the proper byte sizes.
+ */
+ function testCommonParseSize() {
+ foreach ($this->exact_test_cases as $string => $size) {
+ $this->assertEqual(
+ $parsed_size = parse_size($string),
+ $size,
+ $size . ' == ' . $parsed_size . ' (' . $string . ')'
+ );
+ }
+
+ // Some custom parsing tests
+ $string = '23476892 bytes';
+ $this->assertEqual(
+ ($parsed_size = parse_size($string)),
+ $size = 23476892,
+ $string . ' == ' . $parsed_size . ' bytes'
+ );
+ $string = '76MRandomStringThatShouldBeIgnoredByParseSize.'; // 76 MB
+ $this->assertEqual(
+ $parsed_size = parse_size($string),
+ $size = 79691776,
+ $string . ' == ' . $parsed_size . ' bytes'
+ );
+ $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB
+ $this->assertEqual(
+ $parsed_size = parse_size($string),
+ $size = 81862076662,
+ $string . ' == ' . $parsed_size . ' bytes'
+ );
+ }
+
+ /**
+ * Cross-test parse_size() and format_size().
+ */
+ function testCommonParseSizeFormatSize() {
+ foreach ($this->exact_test_cases as $size) {
+ $this->assertEqual(
+ $size,
+ ($parsed_size = parse_size($string = format_size($size, NULL))),
+ $size . ' == ' . $parsed_size . ' (' . $string . ')'
+ );
+ }
+ }
+}
+
+/**
+ * Test drupal_explode_tags() and drupal_implode_tags().
+ */
+class DrupalTagsHandlingTestCase extends DrupalUnitTestCase {
+ var $validTags = array(
+ 'Drupal' => 'Drupal',
+ 'Drupal with some spaces' => 'Drupal with some spaces',
+ '"Legendary Drupal mascot of doom: ""Druplicon"""' => 'Legendary Drupal mascot of doom: "Druplicon"',
+ '"Drupal, although it rhymes with sloopal, is as awesome as a troopal!"' => 'Drupal, although it rhymes with sloopal, is as awesome as a troopal!',
+ );
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Drupal tags handling',
+ 'description' => "Performs tests on Drupal's handling of tags, both explosion and implosion tactics used.",
+ 'group' => 'System'
+ );
+ }
+
+ /**
+ * Explode a series of tags.
+ */
+ function testDrupalExplodeTags() {
+ $string = implode(', ', array_keys($this->validTags));
+ $tags = drupal_explode_tags($string);
+ $this->assertTags($tags);
+ }
+
+ /**
+ * Implode a series of tags.
+ */
+ function testDrupalImplodeTags() {
+ $tags = array_values($this->validTags);
+ // Let's explode and implode to our heart's content.
+ for ($i = 0; $i < 10; $i++) {
+ $string = drupal_implode_tags($tags);
+ $tags = drupal_explode_tags($string);
+ }
+ $this->assertTags($tags);
+ }
+
+ /**
+ * Helper function: asserts that the ending array of tags is what we wanted.
+ */
+ function assertTags($tags) {
+ $original = $this->validTags;
+ foreach ($tags as $tag) {
+ $key = array_search($tag, $original);
+ $this->assertTrue($key, format_string('Make sure tag %tag shows up in the final tags array (originally %original)', array('%tag' => $tag, '%original' => $key)));
+ unset($original[$key]);
+ }
+ foreach ($original as $leftover) {
+ $this->fail(format_string('Leftover tag %leftover was left over.', array('%leftover' => $leftover)));
+ }
+ }
+}
+
+/**
+ * Test the Drupal CSS system.
+ */
+class CascadingStylesheetsTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Cascading stylesheets',
+ 'description' => 'Tests adding various cascading stylesheets to the page.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('php', 'locale', 'common_test');
+ // Reset drupal_add_css() before each test.
+ drupal_static_reset('drupal_add_css');
+ }
+
+ /**
+ * Check default stylesheets as empty.
+ */
+ function testDefault() {
+ $this->assertEqual(array(), drupal_add_css(), 'Default CSS is empty.');
+ }
+
+ /**
+ * Test that stylesheets in module .info files are loaded.
+ */
+ function testModuleInfo() {
+ $this->drupalGet('');
+
+ // Verify common_test.css in a STYLE media="all" tag.
+ $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array(
+ ':media' => 'all',
+ ':filename' => 'tests/common_test.css',
+ ));
+ $this->assertTrue(count($elements), "Stylesheet with media 'all' in module .info file found.");
+
+ // Verify common_test.print.css in a STYLE media="print" tag.
+ $elements = $this->xpath('//style[@media=:media and contains(text(), :filename)]', array(
+ ':media' => 'print',
+ ':filename' => 'tests/common_test.print.css',
+ ));
+ $this->assertTrue(count($elements), "Stylesheet with media 'print' in module .info file found.");
+ }
+
+ /**
+ * Tests adding a file stylesheet.
+ */
+ function testAddFile() {
+ $path = drupal_get_path('module', 'simpletest') . '/simpletest.css';
+ $css = drupal_add_css($path);
+ $this->assertEqual($css[$path]['data'], $path, 'Adding a CSS file caches it properly.');
+ }
+
+ /**
+ * Tests adding an external stylesheet.
+ */
+ function testAddExternal() {
+ $path = 'http://example.com/style.css';
+ $css = drupal_add_css($path, 'external');
+ $this->assertEqual($css[$path]['type'], 'external', 'Adding an external CSS file caches it properly.');
+ }
+
+ /**
+ * Makes sure that reseting the CSS empties the cache.
+ */
+ function testReset() {
+ drupal_static_reset('drupal_add_css');
+ $this->assertEqual(array(), drupal_add_css(), 'Resetting the CSS empties the cache.');
+ }
+
+ /**
+ * Tests rendering the stylesheets.
+ */
+ function testRenderFile() {
+ $css = drupal_get_path('module', 'simpletest') . '/simpletest.css';
+ drupal_add_css($css);
+ $styles = drupal_get_css();
+ $this->assertTrue(strpos($styles, $css) > 0, 'Rendered CSS includes the added stylesheet.');
+ }
+
+ /**
+ * Tests rendering an external stylesheet.
+ */
+ function testRenderExternal() {
+ $css = 'http://example.com/style.css';
+ drupal_add_css($css, 'external');
+ $styles = drupal_get_css();
+ // Stylesheet URL may be the href of a LINK tag or in an @import statement
+ // of a STYLE tag.
+ $this->assertTrue(strpos($styles, 'href="' . $css) > 0 || strpos($styles, '@import url("' . $css . '")') > 0, 'Rendering an external CSS file.');
+ }
+
+ /**
+ * Tests rendering inline stylesheets with preprocessing on.
+ */
+ function testRenderInlinePreprocess() {
+ $css = 'body { padding: 0px; }';
+ $css_preprocessed = '<style type="text/css" media="all">' . "\n<!--/*--><![CDATA[/*><!--*/\n" . drupal_load_stylesheet_content($css, TRUE) . "\n/*]]>*/-->\n" . '</style>';
+ drupal_add_css($css, array('type' => 'inline'));
+ $styles = drupal_get_css();
+ $this->assertEqual(trim($styles), $css_preprocessed, 'Rendering preprocessed inline CSS adds it to the page.');
+ }
+
+ /**
+ * Tests removing charset when rendering stylesheets with preprocessing on.
+ */
+ function testRenderRemoveCharsetPreprocess() {
+ $cases = array(
+ array(
+ 'asset' => '@charset "UTF-8";html{font-family:"sans-serif";}',
+ 'expected' => 'html{font-family:"sans-serif";}',
+ ),
+ // This asset contains extra \n character.
+ array(
+ 'asset' => "@charset 'UTF-8';\nhtml{font-family:'sans-serif';}",
+ 'expected' => "\nhtml{font-family:'sans-serif';}",
+ ),
+ );
+
+ foreach ($cases as $case) {
+ $this->assertEqual(
+ $case['expected'],
+ drupal_load_stylesheet_content($case['asset']),
+ 'CSS optimizing correctly removes the charset declaration.'
+ );
+ }
+ }
+
+ /**
+ * Tests rendering inline stylesheets with preprocessing off.
+ */
+ function testRenderInlineNoPreprocess() {
+ $css = 'body { padding: 0px; }';
+ drupal_add_css($css, array('type' => 'inline', 'preprocess' => FALSE));
+ $styles = drupal_get_css();
+ $this->assertTrue(strpos($styles, $css) > 0, 'Rendering non-preprocessed inline CSS adds it to the page.');
+ }
+
+ /**
+ * Tests rendering inline stylesheets through a full page request.
+ */
+ function testRenderInlineFullPage() {
+ $css = 'body { font-size: 254px; }';
+ // Inline CSS is minified unless 'preprocess' => FALSE is passed as a
+ // drupal_add_css() option.
+ $expected = 'body{font-size:254px;}';
+
+ // Create a node, using the PHP filter that tests drupal_add_css().
+ $php_format_id = 'php_code';
+ $settings = array(
+ 'type' => 'page',
+ 'body' => array(
+ LANGUAGE_NONE => array(
+ array(
+ 'value' => t('This tests the inline CSS!') . "<?php drupal_add_css('$css', 'inline'); ?>",
+ 'format' => $php_format_id,
+ ),
+ ),
+ ),
+ 'promote' => 1,
+ );
+ $node = $this->drupalCreateNode($settings);
+
+ // Fetch the page.
+ $this->drupalGet('node/' . $node->nid);
+ $this->assertRaw($expected, 'Inline stylesheets appear in the full page rendering.');
+ }
+
+ /**
+ * Test CSS ordering.
+ */
+ function testRenderOrder() {
+ // A module CSS file.
+ drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
+ // A few system CSS files, ordered in a strange way.
+ $system_path = drupal_get_path('module', 'system');
+ drupal_add_css($system_path . '/system.menus.css', array('group' => CSS_SYSTEM));
+ drupal_add_css($system_path . '/system.base.css', array('group' => CSS_SYSTEM, 'weight' => -10));
+ drupal_add_css($system_path . '/system.theme.css', array('group' => CSS_SYSTEM));
+
+ $expected = array(
+ $system_path . '/system.base.css',
+ $system_path . '/system.menus.css',
+ $system_path . '/system.theme.css',
+ drupal_get_path('module', 'simpletest') . '/simpletest.css',
+ );
+
+
+ $styles = drupal_get_css();
+ // Stylesheet URL may be the href of a LINK tag or in an @import statement
+ // of a STYLE tag.
+ if (preg_match_all('/(href="|url\(")' . preg_quote($GLOBALS['base_url'] . '/', '/') . '([^?]+)\?/', $styles, $matches)) {
+ $result = $matches[2];
+ }
+ else {
+ $result = array();
+ }
+
+ $this->assertIdentical($result, $expected, 'The CSS files are in the expected order.');
+ }
+
+ /**
+ * Test CSS override.
+ */
+ function testRenderOverride() {
+ $system = drupal_get_path('module', 'system');
+ $simpletest = drupal_get_path('module', 'simpletest');
+
+ drupal_add_css($system . '/system.base.css');
+ drupal_add_css($simpletest . '/tests/system.base.css');
+
+ // The dummy stylesheet should be the only one included.
+ $styles = drupal_get_css();
+ $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') !== FALSE, 'The overriding CSS file is output.');
+ $this->assert(strpos($styles, $system . '/system.base.css') === FALSE, 'The overridden CSS file is not output.');
+
+ drupal_add_css($simpletest . '/tests/system.base.css');
+ drupal_add_css($system . '/system.base.css');
+
+ // The standard stylesheet should be the only one included.
+ $styles = drupal_get_css();
+ $this->assert(strpos($styles, $system . '/system.base.css') !== FALSE, 'The overriding CSS file is output.');
+ $this->assert(strpos($styles, $simpletest . '/tests/system.base.css') === FALSE, 'The overridden CSS file is not output.');
+ }
+
+ /**
+ * Tests Locale module's CSS Alter to include RTL overrides.
+ */
+ function testAlter() {
+ // Switch the language to a right to left language and add system.base.css.
+ global $language;
+ $language->direction = LANGUAGE_RTL;
+ $path = drupal_get_path('module', 'system');
+ drupal_add_css($path . '/system.base.css');
+
+ // Check to see if system.base-rtl.css was also added.
+ $styles = drupal_get_css();
+ $this->assert(strpos($styles, $path . '/system.base-rtl.css') !== FALSE, 'CSS is alterable as right to left overrides are added.');
+
+ // Change the language back to left to right.
+ $language->direction = LANGUAGE_LTR;
+ }
+
+ /**
+ * Tests that the query string remains intact when adding CSS files that have
+ * query string parameters.
+ */
+ function testAddCssFileWithQueryString() {
+ $this->drupalGet('common-test/query-string');
+ $query_string = variable_get('css_js_query_string', '0');
+ $this->assertRaw(drupal_get_path('module', 'node') . '/node.css?' . $query_string, 'Query string was appended correctly to css.');
+ $this->assertRaw(drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&amp;arg2=value2', 'Query string not escaped on a URI.');
+ }
+}
+
+/**
+ * Test for cleaning HTML identifiers.
+ */
+class DrupalHTMLIdentifierTestCase extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'HTML identifiers',
+ 'description' => 'Test the functions drupal_html_class(), drupal_html_id() and drupal_clean_css_identifier() for expected behavior',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Tests that drupal_clean_css_identifier() cleans the identifier properly.
+ */
+ function testDrupalCleanCSSIdentifier() {
+ // Verify that no valid ASCII characters are stripped from the identifier.
+ $identifier = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789';
+ $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, 'Verify valid ASCII characters pass through.');
+
+ // Verify that valid UTF-8 characters are not stripped from the identifier.
+ $identifier = '¡¢£¤¥';
+ $this->assertIdentical(drupal_clean_css_identifier($identifier, array()), $identifier, 'Verify valid UTF-8 characters pass through.');
+
+ // Verify that invalid characters (including non-breaking space) are stripped from the identifier.
+ $this->assertIdentical(drupal_clean_css_identifier('invalid !"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ identifier', array()), 'invalididentifier', 'Strip invalid characters.');
+ }
+
+ /**
+ * Tests that drupal_html_class() cleans the class name properly.
+ */
+ function testDrupalHTMLClass() {
+ // Verify Drupal coding standards are enforced.
+ $this->assertIdentical(drupal_html_class('CLASS NAME_[Ü]'), 'class-name--ü', 'Enforce Drupal coding standards.');
+ }
+
+ /**
+ * Tests that drupal_html_id() cleans the ID properly.
+ */
+ function testDrupalHTMLId() {
+ // Verify that letters, digits, and hyphens are not stripped from the ID.
+ $id = 'abcdefghijklmnopqrstuvwxyz-0123456789';
+ $this->assertIdentical(drupal_html_id($id), $id, 'Verify valid characters pass through.');
+
+ // Verify that invalid characters are stripped from the ID.
+ $this->assertIdentical(drupal_html_id('invalid,./:@\\^`{Üidentifier'), 'invalididentifier', 'Strip invalid characters.');
+
+ // Verify Drupal coding standards are enforced.
+ $this->assertIdentical(drupal_html_id('ID NAME_[1]'), 'id-name-1', 'Enforce Drupal coding standards.');
+
+ // Reset the static cache so we can ensure the unique id count is at zero.
+ drupal_static_reset('drupal_html_id');
+
+ // Clean up IDs with invalid starting characters.
+ $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id', 'Test the uniqueness of IDs #1.');
+ $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--2', 'Test the uniqueness of IDs #2.');
+ $this->assertIdentical(drupal_html_id('test-unique-id'), 'test-unique-id--3', 'Test the uniqueness of IDs #3.');
+ }
+}
+
+/**
+ * CSS Unit Tests.
+ */
+class CascadingStylesheetsUnitTest extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'CSS Unit Tests',
+ 'description' => 'Unit tests on CSS functions like aggregation.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Tests basic CSS loading with and without optimization via drupal_load_stylesheet().
+ *
+ * Known tests:
+ * - Retain white-space in selectors. (http://drupal.org/node/472820)
+ * - Proper URLs in imported files. (http://drupal.org/node/265719)
+ * - Retain pseudo-selectors. (http://drupal.org/node/460448)
+ */
+ function testLoadCssBasic() {
+ // Array of files to test living in 'simpletest/files/css_test_files/'.
+ // - Original: name.css
+ // - Unoptimized expected content: name.css.unoptimized.css
+ // - Optimized expected content: name.css.optimized.css
+ $testfiles = array(
+ 'css_input_without_import.css',
+ 'css_input_with_import.css',
+ 'css_subfolder/css_input_with_import.css',
+ 'comment_hacks.css'
+ );
+ $path = drupal_get_path('module', 'simpletest') . '/files/css_test_files';
+ foreach ($testfiles as $file) {
+ $file_path = $path . '/' . $file;
+ $file_url = $GLOBALS['base_url'] . '/' . $file_path;
+
+ $expected = file_get_contents($file_path . '.unoptimized.css');
+ $unoptimized_output = drupal_load_stylesheet($file_path, FALSE);
+ $this->assertEqual($unoptimized_output, $expected, format_string('Unoptimized CSS file has expected contents (@file)', array('@file' => $file)));
+
+ $expected = file_get_contents($file_path . '.optimized.css');
+ $optimized_output = drupal_load_stylesheet($file_path, TRUE);
+ $this->assertEqual($optimized_output, $expected, format_string('Optimized CSS file has expected contents (@file)', array('@file' => $file)));
+
+ // Repeat the tests by accessing the stylesheets by URL.
+ $expected = file_get_contents($file_path . '.unoptimized.css');
+ $unoptimized_output_url = drupal_load_stylesheet($file_url, FALSE);
+ $this->assertEqual($unoptimized_output_url, $expected, format_string('Unoptimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));
+
+ $expected = file_get_contents($file_path . '.optimized.css');
+ $optimized_output_url = drupal_load_stylesheet($file_url, TRUE);
+ $this->assertEqual($optimized_output_url, $expected, format_string('Optimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));
+ }
+ }
+}
+
+/**
+ * Test drupal_http_request().
+ */
+class DrupalHTTPRequestTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Drupal HTTP request',
+ 'description' => "Performs tests on Drupal's HTTP request mechanism.",
+ 'group' => 'System'
+ );
+ }
+
+ function setUp() {
+ parent::setUp('system_test', 'locale');
+ }
+
+ function testDrupalHTTPRequest() {
+ global $is_https;
+
+ // Parse URL schema.
+ $missing_scheme = drupal_http_request('example.com/path');
+ $this->assertEqual($missing_scheme->code, -1002, 'Returned with "-1002" error code.');
+ $this->assertEqual($missing_scheme->error, 'missing schema', 'Returned with "missing schema" error message.');
+
+ $unable_to_parse = drupal_http_request('http:///path');
+ $this->assertEqual($unable_to_parse->code, -1001, 'Returned with "-1001" error code.');
+ $this->assertEqual($unable_to_parse->error, 'unable to parse URL', 'Returned with "unable to parse URL" error message.');
+
+ // Fetch page.
+ $result = drupal_http_request(url('node', array('absolute' => TRUE)));
+ $this->assertEqual($result->code, 200, 'Fetched page successfully.');
+ $this->drupalSetContent($result->data);
+ $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.');
+
+ // Test that code and status message is returned.
+ $result = drupal_http_request(url('pagedoesnotexist', array('absolute' => TRUE)));
+ $this->assertTrue(!empty($result->protocol), 'Result protocol is returned.');
+ $this->assertEqual($result->code, '404', 'Result code is 404');
+ $this->assertEqual($result->status_message, 'Not Found', 'Result status message is "Not Found"');
+
+ // Skip the timeout tests when the testing environment is HTTPS because
+ // stream_set_timeout() does not work for SSL connections.
+ // @link http://bugs.php.net/bug.php?id=47929
+ if (!$is_https) {
+ // Test that timeout is respected. The test machine is expected to be able
+ // to make the connection (i.e. complete the fsockopen()) in 2 seconds and
+ // return within a total of 5 seconds. If the test machine is extremely
+ // slow, the test will fail. fsockopen() has been seen to time out in
+ // slightly less than the specified timeout, so allow a little slack on
+ // the minimum expected time (i.e. 1.8 instead of 2).
+ timer_start(__METHOD__);
+ $result = drupal_http_request(url('system-test/sleep/10', array('absolute' => TRUE)), array('timeout' => 2));
+ $time = timer_read(__METHOD__) / 1000;
+ $this->assertTrue(1.8 < $time && $time < 5, format_string('Request timed out (%time seconds).', array('%time' => $time)));
+ $this->assertTrue($result->error, 'An error message was returned.');
+ $this->assertEqual($result->code, HTTP_REQUEST_TIMEOUT, 'Proper error code was returned.');
+ }
+ }
+
+ function testDrupalHTTPRequestBasicAuth() {
+ $username = $this->randomName();
+ $password = $this->randomName();
+ $url = url('system-test/auth', array('absolute' => TRUE));
+
+ $auth = str_replace('://', '://' . $username . ':' . $password . '@', $url);
+ $result = drupal_http_request($auth);
+
+ $this->drupalSetContent($result->data);
+ $this->assertRaw($username, '$_SERVER["PHP_AUTH_USER"] is passed correctly.');
+ $this->assertRaw($password, '$_SERVER["PHP_AUTH_PW"] is passed correctly.');
+ }
+
+ function testDrupalHTTPRequestRedirect() {
+ $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_301->redirect_code, 301, 'drupal_http_request follows the 301 redirect.');
+
+ $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 0));
+ $this->assertFalse(isset($redirect_301->redirect_code), 'drupal_http_request does not follow 301 redirect if max_redirects = 0.');
+
+ $redirect_invalid = drupal_http_request(url('system-test/redirect-noscheme', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_invalid->code, -1002, format_string('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error)));
+ $this->assertEqual($redirect_invalid->error, 'missing schema', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
+
+ $redirect_invalid = drupal_http_request(url('system-test/redirect-noparse', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_invalid->code, -1001, format_string('301 redirect to invalid URL returned with error message code "!error".', array('!error' => $redirect_invalid->error)));
+ $this->assertEqual($redirect_invalid->error, 'unable to parse URL', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
+
+ $redirect_invalid = drupal_http_request(url('system-test/redirect-invalid-scheme', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_invalid->code, -1003, format_string('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error)));
+ $this->assertEqual($redirect_invalid->error, 'invalid schema ftp', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error)));
+
+ $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_302->redirect_code, 302, 'drupal_http_request follows the 302 redirect.');
+
+ $redirect_302 = drupal_http_request(url('system-test/redirect/302', array('absolute' => TRUE)), array('max_redirects' => 0));
+ $this->assertFalse(isset($redirect_302->redirect_code), 'drupal_http_request does not follow 302 redirect if $retry = 0.');
+
+ $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($redirect_307->redirect_code, 307, 'drupal_http_request follows the 307 redirect.');
+
+ $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 0));
+ $this->assertFalse(isset($redirect_307->redirect_code), 'drupal_http_request does not follow 307 redirect if max_redirects = 0.');
+
+ $multiple_redirect_final_url = url('system-test/multiple-redirects/0', array('absolute' => TRUE));
+ $multiple_redirect_1 = drupal_http_request(url('system-test/multiple-redirects/1', array('absolute' => TRUE)), array('max_redirects' => 1));
+ $this->assertEqual($multiple_redirect_1->redirect_url, $multiple_redirect_final_url, 'redirect_url contains the final redirection location after 1 redirect.');
+
+ $multiple_redirect_3 = drupal_http_request(url('system-test/multiple-redirects/3', array('absolute' => TRUE)), array('max_redirects' => 3));
+ $this->assertEqual($multiple_redirect_3->redirect_url, $multiple_redirect_final_url, 'redirect_url contains the final redirection location after 3 redirects.');
+ }
+
+ /**
+ * Tests Content-language headers generated by Drupal.
+ */
+ function testDrupalHTTPRequestHeaders() {
+ // Check the default header.
+ $request = drupal_http_request(url('<front>', array('absolute' => TRUE)));
+ $this->assertEqual($request->headers['content-language'], 'en', 'Content-Language HTTP header is English.');
+
+ // Add German language and set as default.
+ locale_add_language('de', 'German', 'Deutsch', LANGUAGE_LTR, '', '', TRUE, TRUE);
+
+ // Request front page and check for matching Content-Language.
+ $request = drupal_http_request(url('<front>', array('absolute' => TRUE)));
+ $this->assertEqual($request->headers['content-language'], 'de', 'Content-Language HTTP header is German.');
+ }
+}
+
+/**
+ * Testing drupal_add_region_content and drupal_get_region_content.
+ */
+class DrupalSetContentTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Drupal set/get regions',
+ 'description' => 'Performs tests on setting and retrieiving content from theme regions.',
+ 'group' => 'System'
+ );
+ }
+
+
+ /**
+ * Test setting and retrieving content for theme regions.
+ */
+ function testRegions() {
+ global $theme_key;
+
+ $block_regions = array_keys(system_region_list($theme_key));
+ $delimiter = $this->randomName(32);
+ $values = array();
+ // Set some random content for each region available.
+ foreach ($block_regions as $region) {
+ $first_chunk = $this->randomName(32);
+ drupal_add_region_content($region, $first_chunk);
+ $second_chunk = $this->randomName(32);
+ drupal_add_region_content($region, $second_chunk);
+ // Store the expected result for a drupal_get_region_content call for this region.
+ $values[$region] = $first_chunk . $delimiter . $second_chunk;
+ }
+
+ // Ensure drupal_get_region_content returns expected results when fetching all regions.
+ $content = drupal_get_region_content(NULL, $delimiter);
+ foreach ($content as $region => $region_content) {
+ $this->assertEqual($region_content, $values[$region], format_string('@region region text verified when fetching all regions', array('@region' => $region)));
+ }
+
+ // Ensure drupal_get_region_content returns expected results when fetching a single region.
+ foreach ($block_regions as $region) {
+ $region_content = drupal_get_region_content($region, $delimiter);
+ $this->assertEqual($region_content, $values[$region], format_string('@region region text verified when fetching single region.', array('@region' => $region)));
+ }
+ }
+}
+
+/**
+ * Testing drupal_goto and hook_drupal_goto_alter().
+ */
+class DrupalGotoTest extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Drupal goto',
+ 'description' => 'Performs tests on the drupal_goto function and hook_drupal_goto_alter',
+ 'group' => 'System'
+ );
+ }
+
+ function setUp() {
+ parent::setUp('common_test');
+ }
+
+ /**
+ * Test drupal_goto().
+ */
+ function testDrupalGoto() {
+ $this->drupalGet('common-test/drupal_goto/redirect');
+ $headers = $this->drupalGetHeaders(TRUE);
+ list(, $status) = explode(' ', $headers[0][':status'], 3);
+ $this->assertEqual($status, 302, 'Expected response code was sent.');
+ $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.');
+ $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), 'Drupal goto redirected to expected URL.');
+
+ $this->drupalGet('common-test/drupal_goto/redirect_advanced');
+ $headers = $this->drupalGetHeaders(TRUE);
+ list(, $status) = explode(' ', $headers[0][':status'], 3);
+ $this->assertEqual($status, 301, 'Expected response code was sent.');
+ $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.');
+ $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to expected URL.');
+
+ // Test that drupal_goto() respects ?destination=xxx. Use an complicated URL
+ // to test that the path is encoded and decoded properly.
+ $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123';
+ $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
+ $this->assertText('drupal_goto', 'Drupal goto redirect with destination succeeded.');
+ $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to given query string destination.');
+ }
+
+ /**
+ * Test hook_drupal_goto_alter().
+ */
+ function testDrupalGotoAlter() {
+ $this->drupalGet('common-test/drupal_goto/redirect_fail');
+
+ $this->assertNoText(t("Drupal goto failed to stop program"), "Drupal goto stopped program.");
+ $this->assertNoText('drupal_goto_fail', "Drupal goto redirect failed.");
+ }
+
+ /**
+ * Test drupal_get_destination().
+ */
+ function testDrupalGetDestination() {
+ $query = $this->randomName(10);
+
+ // Verify that a 'destination' query string is used as destination.
+ $this->drupalGet('common-test/destination', array('query' => array('destination' => $query)));
+ $this->assertText('The destination: ' . $query, 'The given query string destination is determined as destination.');
+
+ // Verify that the current path is used as destination.
+ $this->drupalGet('common-test/destination', array('query' => array($query => NULL)));
+ $url = 'common-test/destination?' . $query;
+ $this->assertText('The destination: ' . $url, 'The current path is determined as destination.');
+ }
+}
+
+/**
+ * Tests for the JavaScript system.
+ */
+class JavaScriptTestCase extends DrupalWebTestCase {
+ /**
+ * Store configured value for JavaScript preprocessing.
+ */
+ protected $preprocess_js = NULL;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'JavaScript',
+ 'description' => 'Tests the JavaScript system.',
+ 'group' => 'System'
+ );
+ }
+
+ function setUp() {
+ // Enable Locale and SimpleTest in the test environment.
+ parent::setUp('locale', 'simpletest', 'common_test');
+
+ // Disable preprocessing
+ $this->preprocess_js = variable_get('preprocess_js', 0);
+ variable_set('preprocess_js', 0);
+
+ // Reset drupal_add_js() and drupal_add_library() statics before each test.
+ drupal_static_reset('drupal_add_js');
+ drupal_static_reset('drupal_add_library');
+ }
+
+ function tearDown() {
+ // Restore configured value for JavaScript preprocessing.
+ variable_set('preprocess_js', $this->preprocess_js);
+ parent::tearDown();
+ }
+
+ /**
+ * Test default JavaScript is empty.
+ */
+ function testDefault() {
+ $this->assertEqual(array(), drupal_add_js(), 'Default JavaScript is empty.');
+ }
+
+ /**
+ * Test adding a JavaScript file.
+ */
+ function testAddFile() {
+ $javascript = drupal_add_js('misc/collapse.js');
+ $this->assertTrue(array_key_exists('misc/jquery.js', $javascript), 'jQuery is added when a file is added.');
+ $this->assertTrue(array_key_exists('misc/drupal.js', $javascript), 'Drupal.js is added when file is added.');
+ $this->assertTrue(array_key_exists('misc/collapse.js', $javascript), 'JavaScript files are correctly added.');
+ $this->assertEqual(base_path(), $javascript['settings']['data'][0]['basePath'], 'Base path JavaScript setting is correctly set.');
+ url('', array('prefix' => &$prefix));
+ $this->assertEqual(empty($prefix) ? '' : $prefix, $javascript['settings']['data'][1]['pathPrefix'], 'Path prefix JavaScript setting is correctly set.');
+ }
+
+ /**
+ * Test adding settings.
+ */
+ function testAddSetting() {
+ $javascript = drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting');
+ $this->assertEqual(280342800, $javascript['settings']['data'][2]['dries'], 'JavaScript setting is set correctly.');
+ $this->assertEqual('rocks', $javascript['settings']['data'][2]['drupal'], 'The other JavaScript setting is set correctly.');
+ }
+
+ /**
+ * Tests adding an external JavaScript File.
+ */
+ function testAddExternal() {
+ $path = 'http://example.com/script.js';
+ $javascript = drupal_add_js($path, 'external');
+ $this->assertTrue(array_key_exists('http://example.com/script.js', $javascript), 'Added an external JavaScript file.');
+ }
+
+ /**
+ * Test drupal_get_js() for JavaScript settings.
+ */
+ function testHeaderSetting() {
+ // Only the second of these two entries should appear in Drupal.settings.
+ drupal_add_js(array('commonTest' => 'commonTestShouldNotAppear'), 'setting');
+ drupal_add_js(array('commonTest' => 'commonTestShouldAppear'), 'setting');
+ // All three of these entries should appear in Drupal.settings.
+ drupal_add_js(array('commonTestArray' => array('commonTestValue0')), 'setting');
+ drupal_add_js(array('commonTestArray' => array('commonTestValue1')), 'setting');
+ drupal_add_js(array('commonTestArray' => array('commonTestValue2')), 'setting');
+ // Only the second of these two entries should appear in Drupal.settings.
+ drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting');
+ drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting');
+
+ $javascript = drupal_get_js('header');
+ $this->assertTrue(strpos($javascript, 'basePath') > 0, 'Rendered JavaScript header returns basePath setting.');
+ $this->assertTrue(strpos($javascript, 'misc/jquery.js') > 0, 'Rendered JavaScript header includes jQuery.');
+ $this->assertTrue(strpos($javascript, 'pathPrefix') > 0, 'Rendered JavaScript header returns pathPrefix setting.');
+
+ // Test whether drupal_add_js can be used to override a previous setting.
+ $this->assertTrue(strpos($javascript, 'commonTestShouldAppear') > 0, 'Rendered JavaScript header returns custom setting.');
+ $this->assertTrue(strpos($javascript, 'commonTestShouldNotAppear') === FALSE, 'drupal_add_js() correctly overrides a custom setting.');
+
+ // Test whether drupal_add_js can be used to add numerically indexed values
+ // to an array.
+ $array_values_appear = strpos($javascript, 'commonTestValue0') > 0 && strpos($javascript, 'commonTestValue1') > 0 && strpos($javascript, 'commonTestValue2') > 0;
+ $this->assertTrue($array_values_appear, 'drupal_add_js() correctly adds settings to the end of an indexed array.');
+
+ // Test whether drupal_add_js can be used to override the entry for an
+ // existing key in an associative array.
+ $associative_array_override = strpos($javascript, 'commonTestNewValue') > 0 && strpos($javascript, 'commonTestOldValue') === FALSE;
+ $this->assertTrue($associative_array_override, 'drupal_add_js() correctly overrides settings within an associative array.');
+ }
+
+ /**
+ * Test to see if resetting the JavaScript empties the cache.
+ */
+ function testReset() {
+ drupal_add_js('misc/collapse.js');
+ drupal_static_reset('drupal_add_js');
+ $this->assertEqual(array(), drupal_add_js(), 'Resetting the JavaScript correctly empties the cache.');
+ }
+
+ /**
+ * Test adding inline scripts.
+ */
+ function testAddInline() {
+ $inline = 'jQuery(function () { });';
+ $javascript = drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+ $this->assertTrue(array_key_exists('misc/jquery.js', $javascript), 'jQuery is added when inline scripts are added.');
+ $data = end($javascript);
+ $this->assertEqual($inline, $data['data'], 'Inline JavaScript is correctly added to the footer.');
+ }
+
+ /**
+ * Test rendering an external JavaScript file.
+ */
+ function testRenderExternal() {
+ $external = 'http://example.com/example.js';
+ drupal_add_js($external, 'external');
+ $javascript = drupal_get_js();
+ // Local files have a base_path() prefix, external files should not.
+ $this->assertTrue(strpos($javascript, 'src="' . $external) > 0, 'Rendering an external JavaScript file.');
+ }
+
+ /**
+ * Test drupal_get_js() with a footer scope.
+ */
+ function testFooterHTML() {
+ $inline = 'jQuery(function () { });';
+ drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+ $javascript = drupal_get_js('footer');
+ $this->assertTrue(strpos($javascript, $inline) > 0, 'Rendered JavaScript footer returns the inline code.');
+ }
+
+ /**
+ * Test drupal_add_js() sets preproccess to false when cache is set to false.
+ */
+ function testNoCache() {
+ $javascript = drupal_add_js('misc/collapse.js', array('cache' => FALSE));
+ $this->assertFalse($javascript['misc/collapse.js']['preprocess'], 'Setting cache to FALSE sets proprocess to FALSE when adding JavaScript.');
+ }
+
+ /**
+ * Test adding a JavaScript file with a different group.
+ */
+ function testDifferentGroup() {
+ $javascript = drupal_add_js('misc/collapse.js', array('group' => JS_THEME));
+ $this->assertEqual($javascript['misc/collapse.js']['group'], JS_THEME, 'Adding a JavaScript file with a different group caches the given group.');
+ }
+
+ /**
+ * Test adding a JavaScript file with a different weight.
+ */
+ function testDifferentWeight() {
+ $javascript = drupal_add_js('misc/collapse.js', array('weight' => 2));
+ $this->assertEqual($javascript['misc/collapse.js']['weight'], 2, 'Adding a JavaScript file with a different weight caches the given weight.');
+ }
+
+ /**
+ * Tests JavaScript aggregation when files are added to a different scope.
+ */
+ function testAggregationOrder() {
+ // Enable JavaScript aggregation.
+ variable_set('preprocess_js', 1);
+ drupal_static_reset('drupal_add_js');
+
+ // Add two JavaScript files to the current request and build the cache.
+ drupal_add_js('misc/ajax.js');
+ drupal_add_js('misc/autocomplete.js');
+
+ $js_items = drupal_add_js();
+ drupal_build_js_cache(array(
+ 'misc/ajax.js' => $js_items['misc/ajax.js'],
+ 'misc/autocomplete.js' => $js_items['misc/autocomplete.js']
+ ));
+
+ // Store the expected key for the first item in the cache.
+ $cache = array_keys(variable_get('drupal_js_cache_files', array()));
+ $expected_key = $cache[0];
+
+ // Reset variables and add a file in a different scope first.
+ variable_del('drupal_js_cache_files');
+ drupal_static_reset('drupal_add_js');
+ drupal_add_js('some/custom/javascript_file.js', array('scope' => 'footer'));
+ drupal_add_js('misc/ajax.js');
+ drupal_add_js('misc/autocomplete.js');
+
+ // Rebuild the cache.
+ $js_items = drupal_add_js();
+ drupal_build_js_cache(array(
+ 'misc/ajax.js' => $js_items['misc/ajax.js'],
+ 'misc/autocomplete.js' => $js_items['misc/autocomplete.js']
+ ));
+
+ // Compare the expected key for the first file to the current one.
+ $cache = array_keys(variable_get('drupal_js_cache_files', array()));
+ $key = $cache[0];
+ $this->assertEqual($key, $expected_key, 'JavaScript aggregation is not affected by ordering in different scopes.');
+ }
+
+ /**
+ * Test JavaScript ordering.
+ */
+ function testRenderOrder() {
+ // Add a bunch of JavaScript in strange ordering.
+ drupal_add_js('(function($){alert("Weight 5 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5));
+ drupal_add_js('(function($){alert("Weight 0 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
+ drupal_add_js('(function($){alert("Weight 0 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
+ drupal_add_js('(function($){alert("Weight -8 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
+ drupal_add_js('(function($){alert("Weight -8 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
+ drupal_add_js('(function($){alert("Weight -8 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
+ drupal_add_js('http://example.com/example.js?Weight -5 #1', array('type' => 'external', 'scope' => 'footer', 'weight' => -5));
+ drupal_add_js('(function($){alert("Weight -8 #4");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
+ drupal_add_js('(function($){alert("Weight 5 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5));
+ drupal_add_js('(function($){alert("Weight 0 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
+
+ // Construct the expected result from the regex.
+ $expected = array(
+ "-8 #1",
+ "-8 #2",
+ "-8 #3",
+ "-8 #4",
+ "-5 #1", // The external script.
+ "0 #1",
+ "0 #2",
+ "0 #3",
+ "5 #1",
+ "5 #2",
+ );
+
+ // Retrieve the rendered JavaScript and test against the regex.
+ $js = drupal_get_js('footer');
+ $matches = array();
+ if (preg_match_all('/Weight\s([-0-9]+\s[#0-9]+)/', $js, $matches)) {
+ $result = $matches[1];
+ }
+ else {
+ $result = array();
+ }
+ $this->assertIdentical($result, $expected, 'JavaScript is added in the expected weight order.');
+ }
+
+ /**
+ * Test rendering the JavaScript with a file's weight above jQuery's.
+ */
+ function testRenderDifferentWeight() {
+ // JavaScript files are sorted first by group, then by the 'every_page'
+ // flag, then by weight (see drupal_sort_css_js()), so to test the effect of
+ // weight, we need the other two options to be the same.
+ drupal_add_js('misc/collapse.js', array('group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -21));
+ $javascript = drupal_get_js();
+ $this->assertTrue(strpos($javascript, 'misc/collapse.js') < strpos($javascript, 'misc/jquery.js'), 'Rendering a JavaScript file above jQuery.');
+ }
+
+ /**
+ * Test altering a JavaScript's weight via hook_js_alter().
+ *
+ * @see simpletest_js_alter()
+ */
+ function testAlter() {
+ // Add both tableselect.js and simpletest.js, with a larger weight on SimpleTest.
+ drupal_add_js('misc/tableselect.js');
+ drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('weight' => 9999));
+
+ // Render the JavaScript, testing if simpletest.js was altered to be before
+ // tableselect.js. See simpletest_js_alter() to see where this alteration
+ // takes place.
+ $javascript = drupal_get_js();
+ $this->assertTrue(strpos($javascript, 'simpletest.js') < strpos($javascript, 'misc/tableselect.js'), 'Altering JavaScript weight through the alter hook.');
+ }
+
+ /**
+ * Adds a library to the page and tests for both its JavaScript and its CSS.
+ */
+ function testLibraryRender() {
+ $result = drupal_add_library('system', 'farbtastic');
+ $this->assertTrue($result !== FALSE, 'Library was added without errors.');
+ $scripts = drupal_get_js();
+ $styles = drupal_get_css();
+ $this->assertTrue(strpos($scripts, 'misc/farbtastic/farbtastic.js'), 'JavaScript of library was added to the page.');
+ $this->assertTrue(strpos($styles, 'misc/farbtastic/farbtastic.css'), 'Stylesheet of library was added to the page.');
+ }
+
+ /**
+ * Adds a JavaScript library to the page and alters it.
+ *
+ * @see common_test_library_alter()
+ */
+ function testLibraryAlter() {
+ // Verify that common_test altered the title of Farbtastic.
+ $library = drupal_get_library('system', 'farbtastic');
+ $this->assertEqual($library['title'], 'Farbtastic: Altered Library', 'Registered libraries were altered.');
+
+ // common_test_library_alter() also added a dependency on jQuery Form.
+ drupal_add_library('system', 'farbtastic');
+ $scripts = drupal_get_js();
+ $this->assertTrue(strpos($scripts, 'misc/jquery.form.js'), 'Altered library dependencies are added to the page.');
+ }
+
+ /**
+ * Tests that multiple modules can implement the same library.
+ *
+ * @see common_test_library()
+ */
+ function testLibraryNameConflicts() {
+ $farbtastic = drupal_get_library('common_test', 'farbtastic');
+ $this->assertEqual($farbtastic['title'], 'Custom Farbtastic Library', 'Alternative libraries can be added to the page.');
+ }
+
+ /**
+ * Tests non-existing libraries.
+ */
+ function testLibraryUnknown() {
+ $result = drupal_get_library('unknown', 'unknown');
+ $this->assertFalse($result, 'Unknown library returned FALSE.');
+ drupal_static_reset('drupal_get_library');
+
+ $result = drupal_add_library('unknown', 'unknown');
+ $this->assertFalse($result, 'Unknown library returned FALSE.');
+ $scripts = drupal_get_js();
+ $this->assertTrue(strpos($scripts, 'unknown') === FALSE, 'Unknown library was not added to the page.');
+ }
+
+ /**
+ * Tests the addition of libraries through the #attached['library'] property.
+ */
+ function testAttachedLibrary() {
+ $element['#attached']['library'][] = array('system', 'farbtastic');
+ drupal_render($element);
+ $scripts = drupal_get_js();
+ $this->assertTrue(strpos($scripts, 'misc/farbtastic/farbtastic.js'), 'The attached_library property adds the additional libraries.');
+ }
+
+ /**
+ * Tests retrieval of libraries via drupal_get_library().
+ */
+ function testGetLibrary() {
+ // Retrieve all libraries registered by a module.
+ $libraries = drupal_get_library('common_test');
+ $this->assertTrue(isset($libraries['farbtastic']), 'Retrieved all module libraries.');
+ // Retrieve all libraries for a module not implementing hook_library().
+ // Note: This test installs Locale module.
+ $libraries = drupal_get_library('locale');
+ $this->assertEqual($libraries, array(), 'Retrieving libraries from a module not implementing hook_library() returns an emtpy array.');
+
+ // Retrieve a specific library by module and name.
+ $farbtastic = drupal_get_library('common_test', 'farbtastic');
+ $this->assertEqual($farbtastic['version'], '5.3', 'Retrieved a single library.');
+ // Retrieve a non-existing library by module and name.
+ $farbtastic = drupal_get_library('common_test', 'foo');
+ $this->assertIdentical($farbtastic, FALSE, 'Retrieving a non-existing library returns FALSE.');
+ }
+
+ /**
+ * Tests that the query string remains intact when adding JavaScript files
+ * that have query string parameters.
+ */
+ function testAddJsFileWithQueryString() {
+ $this->drupalGet('common-test/query-string');
+ $query_string = variable_get('css_js_query_string', '0');
+ $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, 'Query string was appended correctly to js.');
+ }
+}
+
+/**
+ * Tests for drupal_render().
+ */
+class DrupalRenderTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'drupal_render()',
+ 'description' => 'Performs functional tests on drupal_render().',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('common_test');
+ }
+
+ /**
+ * Tests the output drupal_render() for some elementary input values.
+ */
+ function testDrupalRenderBasics() {
+ $types = array(
+ array(
+ 'name' => 'null',
+ 'value' => NULL,
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'no value',
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'empty string',
+ 'value' => '',
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'no access',
+ 'value' => array(
+ '#markup' => 'foo',
+ '#access' => FALSE,
+ ),
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'previously printed',
+ 'value' => array(
+ '#markup' => 'foo',
+ '#printed' => TRUE,
+ ),
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'printed in prerender',
+ 'value' => array(
+ '#markup' => 'foo',
+ '#pre_render' => array('common_test_drupal_render_printing_pre_render'),
+ ),
+ 'expected' => '',
+ ),
+ array(
+ 'name' => 'basic renderable array',
+ 'value' => array('#markup' => 'foo'),
+ 'expected' => 'foo',
+ ),
+ );
+ foreach($types as $type) {
+ $this->assertIdentical(drupal_render($type['value']), $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().');
+ }
+ }
+
+ /**
+ * Test sorting by weight.
+ */
+ function testDrupalRenderSorting() {
+ $first = $this->randomName();
+ $second = $this->randomName();
+ // Build an array with '#weight' set for each element.
+ $elements = array(
+ 'second' => array(
+ '#weight' => 10,
+ '#markup' => $second,
+ ),
+ 'first' => array(
+ '#weight' => 0,
+ '#markup' => $first,
+ ),
+ );
+ $output = drupal_render($elements);
+
+ // The lowest weight element should appear last in $output.
+ $this->assertTrue(strpos($output, $second) > strpos($output, $first), 'Elements were sorted correctly by weight.');
+
+ // Confirm that the $elements array has '#sorted' set to TRUE.
+ $this->assertTrue($elements['#sorted'], "'#sorted' => TRUE was added to the array");
+
+ // Pass $elements through element_children() and ensure it remains
+ // sorted in the correct order. drupal_render() will return an empty string
+ // if used on the same array in the same request.
+ $children = element_children($elements);
+ $this->assertTrue(array_shift($children) == 'first', 'Child found in the correct order.');
+ $this->assertTrue(array_shift($children) == 'second', 'Child found in the correct order.');
+
+
+ // The same array structure again, but with #sorted set to TRUE.
+ $elements = array(
+ 'second' => array(
+ '#weight' => 10,
+ '#markup' => $second,
+ ),
+ 'first' => array(
+ '#weight' => 0,
+ '#markup' => $first,
+ ),
+ '#sorted' => TRUE,
+ );
+ $output = drupal_render($elements);
+
+ // The elements should appear in output in the same order as the array.
+ $this->assertTrue(strpos($output, $second) < strpos($output, $first), 'Elements were not sorted.');
+ }
+
+ /**
+ * Test #attached functionality in children elements.
+ */
+ function testDrupalRenderChildrenAttached() {
+ // The cache system is turned off for POST requests.
+ $request_method = $_SERVER['REQUEST_METHOD'];
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+
+ // Create an element with a child and subchild. Each element loads a
+ // different JavaScript file using #attached.
+ $parent_js = drupal_get_path('module', 'user') . '/user.js';
+ $child_js = drupal_get_path('module', 'forum') . '/forum.js';
+ $subchild_js = drupal_get_path('module', 'book') . '/book.js';
+ $element = array(
+ '#type' => 'fieldset',
+ '#cache' => array(
+ 'keys' => array('simpletest', 'drupal_render', 'children_attached'),
+ ),
+ '#attached' => array('js' => array($parent_js)),
+ '#title' => 'Parent',
+ );
+ $element['child'] = array(
+ '#type' => 'fieldset',
+ '#attached' => array('js' => array($child_js)),
+ '#title' => 'Child',
+ );
+ $element['child']['subchild'] = array(
+ '#attached' => array('js' => array($subchild_js)),
+ '#markup' => 'Subchild',
+ );
+
+ // Render the element and verify the presence of #attached JavaScript.
+ drupal_render($element);
+ $scripts = drupal_get_js();
+ $this->assertTrue(strpos($scripts, $parent_js), 'The element #attached JavaScript was included.');
+ $this->assertTrue(strpos($scripts, $child_js), 'The child #attached JavaScript was included.');
+ $this->assertTrue(strpos($scripts, $subchild_js), 'The subchild #attached JavaScript was included.');
+
+ // Load the element from cache and verify the presence of the #attached
+ // JavaScript.
+ drupal_static_reset('drupal_add_js');
+ $this->assertTrue(drupal_render_cache_get($element), 'The element was retrieved from cache.');
+ $scripts = drupal_get_js();
+ $this->assertTrue(strpos($scripts, $parent_js), 'The element #attached JavaScript was included when loading from cache.');
+ $this->assertTrue(strpos($scripts, $child_js), 'The child #attached JavaScript was included when loading from cache.');
+ $this->assertTrue(strpos($scripts, $subchild_js), 'The subchild #attached JavaScript was included when loading from cache.');
+
+ $_SERVER['REQUEST_METHOD'] = $request_method;
+ }
+
+ /**
+ * Test passing arguments to the theme function.
+ */
+ function testDrupalRenderThemeArguments() {
+ $element = array(
+ '#theme' => 'common_test_foo',
+ );
+ // Test that defaults work.
+ $this->assertEqual(drupal_render($element), 'foobar', 'Defaults work');
+ $element = array(
+ '#theme' => 'common_test_foo',
+ '#foo' => $this->randomName(),
+ '#bar' => $this->randomName(),
+ );
+ // Test that passing arguments to the theme function works.
+ $this->assertEqual(drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
+ }
+
+ /**
+ * Test rendering form elements without passing through form_builder().
+ */
+ function testDrupalRenderFormElements() {
+ // Define a series of form elements.
+ $element = array(
+ '#type' => 'button',
+ '#value' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'submit'));
+
+ $element = array(
+ '#type' => 'textfield',
+ '#title' => $this->randomName(),
+ '#value' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'text'));
+
+ $element = array(
+ '#type' => 'password',
+ '#title' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'password'));
+
+ $element = array(
+ '#type' => 'textarea',
+ '#title' => $this->randomName(),
+ '#value' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//textarea');
+
+ $element = array(
+ '#type' => 'radio',
+ '#title' => $this->randomName(),
+ '#value' => FALSE,
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'radio'));
+
+ $element = array(
+ '#type' => 'checkbox',
+ '#title' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'checkbox'));
+
+ $element = array(
+ '#type' => 'select',
+ '#title' => $this->randomName(),
+ '#options' => array(
+ 0 => $this->randomName(),
+ 1 => $this->randomName(),
+ ),
+ );
+ $this->assertRenderedElement($element, '//select');
+
+ $element = array(
+ '#type' => 'file',
+ '#title' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'file'));
+
+ $element = array(
+ '#type' => 'item',
+ '#title' => $this->randomName(),
+ '#markup' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//div[contains(@class, :class) and contains(., :markup)]/label[contains(., :label)]', array(
+ ':class' => 'form-type-item',
+ ':markup' => $element['#markup'],
+ ':label' => $element['#title'],
+ ));
+
+ $element = array(
+ '#type' => 'hidden',
+ '#title' => $this->randomName(),
+ '#value' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//input[@type=:type]', array(':type' => 'hidden'));
+
+ $element = array(
+ '#type' => 'link',
+ '#title' => $this->randomName(),
+ '#href' => $this->randomName(),
+ '#options' => array(
+ 'absolute' => TRUE,
+ ),
+ );
+ $this->assertRenderedElement($element, '//a[@href=:href and contains(., :title)]', array(
+ ':href' => url($element['#href'], array('absolute' => TRUE)),
+ ':title' => $element['#title'],
+ ));
+
+ $element = array(
+ '#type' => 'fieldset',
+ '#title' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//fieldset/legend[contains(., :title)]', array(
+ ':title' => $element['#title'],
+ ));
+
+ $element['item'] = array(
+ '#type' => 'item',
+ '#title' => $this->randomName(),
+ '#markup' => $this->randomName(),
+ );
+ $this->assertRenderedElement($element, '//fieldset/div/div[contains(@class, :class) and contains(., :markup)]', array(
+ ':class' => 'form-type-item',
+ ':markup' => $element['item']['#markup'],
+ ));
+ }
+
+ protected function assertRenderedElement(array $element, $xpath, array $xpath_args = array()) {
+ $original_element = $element;
+ $this->drupalSetContent(drupal_render($element));
+ $this->verbose('<pre>' . check_plain(var_export($original_element, TRUE)) . '</pre>'
+ . '<pre>' . check_plain(var_export($element, TRUE)) . '</pre>'
+ . '<hr />' . $this->drupalGetContent()
+ );
+
+ // @see DrupalWebTestCase::xpath()
+ $xpath = $this->buildXPathQuery($xpath, $xpath_args);
+ $element += array('#value' => NULL);
+ $this->assertFieldByXPath($xpath, $element['#value'], format_string('#type @type was properly rendered.', array(
+ '@type' => var_export($element['#type'], TRUE),
+ )));
+ }
+
+ /**
+ * Tests caching of an empty render item.
+ */
+ function testDrupalRenderCache() {
+ // Force a request via GET.
+ $request_method = $_SERVER['REQUEST_METHOD'];
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ // Create an empty element.
+ $test_element = array(
+ '#cache' => array(
+ 'cid' => 'render_cache_test',
+ ),
+ '#markup' => '',
+ );
+
+ // Render the element and confirm that it goes through the rendering
+ // process (which will set $element['#printed']).
+ $element = $test_element;
+ drupal_render($element);
+ $this->assertTrue(isset($element['#printed']), 'No cache hit');
+
+ // Render the element again and confirm that it is retrieved from the cache
+ // instead (so $element['#printed'] will not be set).
+ $element = $test_element;
+ drupal_render($element);
+ $this->assertFalse(isset($element['#printed']), 'Cache hit');
+
+ // Restore the previous request method.
+ $_SERVER['REQUEST_METHOD'] = $request_method;
+ }
+}
+
+/**
+ * Test for valid_url().
+ */
+class ValidUrlTestCase extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Valid URL',
+ 'description' => "Performs tests on Drupal's valid URL function.",
+ 'group' => 'System'
+ );
+ }
+
+ /**
+ * Test valid absolute URLs.
+ */
+ function testValidAbsolute() {
+ $url_schemes = array('http', 'https', 'ftp');
+ $valid_absolute_urls = array(
+ 'example.com',
+ 'www.example.com',
+ 'ex-ample.com',
+ '3xampl3.com',
+ 'example.com/paren(the)sis',
+ 'example.com/index.html#pagetop',
+ 'example.com:8080',
+ 'subdomain.example.com',
+ 'example.com/index.php?q=node',
+ 'example.com/index.php?q=node&param=false',
+ 'user@www.example.com',
+ 'user:pass@www.example.com:8080/login.php?do=login&style=%23#pagetop',
+ '127.0.0.1',
+ 'example.org?',
+ 'john%20doe:secret:foo@example.org/',
+ 'example.org/~,$\'*;',
+ 'caf%C3%A9.example.org',
+ '[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html',
+ );
+
+ foreach ($url_schemes as $scheme) {
+ foreach ($valid_absolute_urls as $url) {
+ $test_url = $scheme . '://' . $url;
+ $valid_url = valid_url($test_url, TRUE);
+ $this->assertTrue($valid_url, format_string('@url is a valid url.', array('@url' => $test_url)));
+ }
+ }
+ }
+
+ /**
+ * Test invalid absolute URLs.
+ */
+ function testInvalidAbsolute() {
+ $url_schemes = array('http', 'https', 'ftp');
+ $invalid_ablosule_urls = array(
+ '',
+ 'ex!ample.com',
+ 'ex%ample.com',
+ );
+
+ foreach ($url_schemes as $scheme) {
+ foreach ($invalid_ablosule_urls as $url) {
+ $test_url = $scheme . '://' . $url;
+ $valid_url = valid_url($test_url, TRUE);
+ $this->assertFalse($valid_url, format_string('@url is NOT a valid url.', array('@url' => $test_url)));
+ }
+ }
+ }
+
+ /**
+ * Test valid relative URLs.
+ */
+ function testValidRelative() {
+ $valid_relative_urls = array(
+ 'paren(the)sis',
+ 'index.html#pagetop',
+ 'index.php?q=node',
+ 'index.php?q=node&param=false',
+ 'login.php?do=login&style=%23#pagetop',
+ );
+
+ foreach (array('', '/') as $front) {
+ foreach ($valid_relative_urls as $url) {
+ $test_url = $front . $url;
+ $valid_url = valid_url($test_url);
+ $this->assertTrue($valid_url, format_string('@url is a valid url.', array('@url' => $test_url)));
+ }
+ }
+ }
+
+ /**
+ * Test invalid relative URLs.
+ */
+ function testInvalidRelative() {
+ $invalid_relative_urls = array(
+ 'ex^mple',
+ 'example<>',
+ 'ex%ample',
+ );
+
+ foreach (array('', '/') as $front) {
+ foreach ($invalid_relative_urls as $url) {
+ $test_url = $front . $url;
+ $valid_url = valid_url($test_url);
+ $this->assertFALSE($valid_url, format_string('@url is NOT a valid url.', array('@url' => $test_url)));
+ }
+ }
+ }
+}
+
+/**
+ * Tests for CRUD API functions.
+ */
+class DrupalDataApiTest extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Data API functions',
+ 'description' => 'Tests the performance of CRUD APIs.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('database_test');
+ }
+
+ /**
+ * Test the drupal_write_record() API function.
+ */
+ function testDrupalWriteRecord() {
+ // Insert a record - no columns allow NULL values.
+ $person = new stdClass();
+ $person->name = 'John';
+ $person->unknown_column = 123;
+ $insert_result = drupal_write_record('test', $person);
+ $this->assertTrue($insert_result == SAVED_NEW, 'Correct value returned when a record is inserted with drupal_write_record() for a table with a single-field primary key.');
+ $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().');
+ $this->assertIdentical($person->age, 0, 'Age field set to default value.');
+ $this->assertIdentical($person->job, 'Undefined', 'Job field set to default value.');
+
+ // Verify that the record was inserted.
+ $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'John', 'Name field set.');
+ $this->assertIdentical($result->age, '0', 'Age field set to default value.');
+ $this->assertIdentical($result->job, 'Undefined', 'Job field set to default value.');
+ $this->assertFalse(isset($result->unknown_column), 'Unknown column was ignored.');
+
+ // Update the newly created record.
+ $person->name = 'Peter';
+ $person->age = 27;
+ $person->job = NULL;
+ $update_result = drupal_write_record('test', $person, array('id'));
+ $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a record updated with drupal_write_record() for table with single-field primary key.');
+
+ // Verify that the record was updated.
+ $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Peter', 'Name field set.');
+ $this->assertIdentical($result->age, '27', 'Age field set.');
+ $this->assertIdentical($result->job, '', 'Job field set and cast to string.');
+
+ // Try to insert NULL in columns that does not allow this.
+ $person = new stdClass();
+ $person->name = 'Ringo';
+ $person->age = NULL;
+ $person->job = NULL;
+ $insert_result = drupal_write_record('test', $person);
+ $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().');
+ $result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Ringo', 'Name field set.');
+ $this->assertIdentical($result->age, '0', 'Age field set.');
+ $this->assertIdentical($result->job, '', 'Job field set.');
+
+ // Insert a record - the "age" column allows NULL.
+ $person = new stdClass();
+ $person->name = 'Paul';
+ $person->age = NULL;
+ $insert_result = drupal_write_record('test_null', $person);
+ $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().');
+ $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Paul', 'Name field set.');
+ $this->assertIdentical($result->age, NULL, 'Age field set.');
+
+ // Insert a record - do not specify the value of a column that allows NULL.
+ $person = new stdClass();
+ $person->name = 'Meredith';
+ $insert_result = drupal_write_record('test_null', $person);
+ $this->assertTrue(isset($person->id), 'Primary key is set on record created with drupal_write_record().');
+ $this->assertIdentical($person->age, 0, 'Age field set to default value.');
+ $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Meredith', 'Name field set.');
+ $this->assertIdentical($result->age, '0', 'Age field set to default value.');
+
+ // Update the newly created record.
+ $person->name = 'Mary';
+ $person->age = NULL;
+ $update_result = drupal_write_record('test_null', $person, array('id'));
+ $result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Mary', 'Name field set.');
+ $this->assertIdentical($result->age, NULL, 'Age field set.');
+
+ // Insert a record - the "data" column should be serialized.
+ $person = new stdClass();
+ $person->name = 'Dave';
+ $update_result = drupal_write_record('test_serialized', $person);
+ $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical($result->name, 'Dave', 'Name field set.');
+ $this->assertIdentical($result->info, NULL, 'Info field set.');
+
+ $person->info = array();
+ $update_result = drupal_write_record('test_serialized', $person, array('id'));
+ $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical(unserialize($result->info), array(), 'Info field updated.');
+
+ // Update the serialized record.
+ $data = array('foo' => 'bar', 1 => 2, 'empty' => '', 'null' => NULL);
+ $person->info = $data;
+ $update_result = drupal_write_record('test_serialized', $person, array('id'));
+ $result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
+ $this->assertIdentical(unserialize($result->info), $data, 'Info field updated.');
+
+ // Run an update query where no field values are changed. The database
+ // layer should return zero for number of affected rows, but
+ // db_write_record() should still return SAVED_UPDATED.
+ $update_result = drupal_write_record('test_null', $person, array('id'));
+ $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a valid update is run without changing any values.');
+
+ // Insert an object record for a table with a multi-field primary key.
+ $node_access = new stdClass();
+ $node_access->nid = mt_rand();
+ $node_access->gid = mt_rand();
+ $node_access->realm = $this->randomName();
+ $insert_result = drupal_write_record('node_access', $node_access);
+ $this->assertTrue($insert_result == SAVED_NEW, 'Correct value returned when a record is inserted with drupal_write_record() for a table with a multi-field primary key.');
+
+ // Update the record.
+ $update_result = drupal_write_record('node_access', $node_access, array('nid', 'gid', 'realm'));
+ $this->assertTrue($update_result == SAVED_UPDATED, 'Correct value returned when a record is updated with drupal_write_record() for a table with a multi-field primary key.');
+ }
+
+}
+
+/**
+ * Tests Simpletest error and exception collector.
+ */
+class DrupalErrorCollectionUnitTest extends DrupalWebTestCase {
+
+ /**
+ * Errors triggered during the test.
+ *
+ * Errors are intercepted by the overriden implementation
+ * of DrupalWebTestCase::error below.
+ *
+ * @var Array
+ */
+ protected $collectedErrors = array();
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'SimpleTest error collector',
+ 'description' => 'Performs tests on the Simpletest error and exception collector.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('system_test', 'error_test');
+ }
+
+ /**
+ * Test that simpletest collects errors from the tested site.
+ */
+ function testErrorCollect() {
+ $this->collectedErrors = array();
+ $this->drupalGet('error-test/generate-warnings-with-report');
+ $this->assertEqual(count($this->collectedErrors), 3, 'Three errors were collected');
+
+ if (count($this->collectedErrors) == 3) {
+ $this->assertError($this->collectedErrors[0], 'Notice', 'error_test_generate_warnings()', 'error_test.module', 'Undefined variable: bananas');
+ $this->assertError($this->collectedErrors[1], 'Warning', 'error_test_generate_warnings()', 'error_test.module', 'Division by zero');
+ $this->assertError($this->collectedErrors[2], 'User warning', 'error_test_generate_warnings()', 'error_test.module', 'Drupal is awesome');
+ }
+ else {
+ // Give back the errors to the log report.
+ foreach ($this->collectedErrors as $error) {
+ parent::error($error['message'], $error['group'], $error['caller']);
+ }
+ }
+ }
+
+ /**
+ * Error handler that collects errors in an array.
+ *
+ * This test class is trying to verify that simpletest correctly sees errors
+ * and warnings. However, it can't generate errors and warnings that
+ * propagate up to the testing framework itself, or these tests would always
+ * fail. So, this special copy of error() doesn't propagate the errors up
+ * the class hierarchy. It just stuffs them into a protected collectedErrors
+ * array for various assertions to inspect.
+ */
+ protected function error($message = '', $group = 'Other', array $caller = NULL) {
+ // Due to a WTF elsewhere, simpletest treats debug() and verbose()
+ // messages as if they were an 'error'. But, we don't want to collect
+ // those here. This function just wants to collect the real errors (PHP
+ // notices, PHP fatal errors, etc.), and let all the 'errors' from the
+ // 'User notice' group bubble up to the parent classes to be handled (and
+ // eventually displayed) as normal.
+ if ($group == 'User notice') {
+ parent::error($message, $group, $caller);
+ }
+ // Everything else should be collected but not propagated.
+ else {
+ $this->collectedErrors[] = array(
+ 'message' => $message,
+ 'group' => $group,
+ 'caller' => $caller
+ );
+ }
+ }
+
+ /**
+ * Assert that a collected error matches what we are expecting.
+ */
+ function assertError($error, $group, $function, $file, $message = NULL) {
+ $this->assertEqual($error['group'], $group, format_string("Group was %group", array('%group' => $group)));
+ $this->assertEqual($error['caller']['function'], $function, format_string("Function was %function", array('%function' => $function)));
+ $this->assertEqual(drupal_basename($error['caller']['file']), $file, format_string("File was %file", array('%file' => $file)));
+ if (isset($message)) {
+ $this->assertEqual($error['message'], $message, format_string("Message was %message", array('%message' => $message)));
+ }
+ }
+}
+
+/**
+ * Test the drupal_parse_info_file() API function.
+ */
+class ParseInfoFilesTestCase extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Parsing .info files',
+ 'description' => 'Tests parsing .info files.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Parse an example .info file an verify the results.
+ */
+ function testParseInfoFile() {
+ $info_values = drupal_parse_info_file(drupal_get_path('module', 'simpletest') . '/tests/common_test_info.txt');
+ $this->assertEqual($info_values['simple_string'], 'A simple string', 'Simple string value was parsed correctly.', 'System');
+ $this->assertEqual($info_values['simple_constant'], WATCHDOG_INFO, 'Constant value was parsed correctly.', 'System');
+ $this->assertEqual($info_values['double_colon'], 'dummyClassName::', 'Value containing double-colon was parsed correctly.', 'System');
+ }
+}
+
+/**
+ * Tests for the drupal_system_listing() function.
+ */
+class DrupalSystemListingTestCase extends DrupalWebTestCase {
+ /**
+ * Use the testing profile; this is needed for testDirectoryPrecedence().
+ */
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Drupal system listing',
+ 'description' => 'Tests the mechanism for scanning system directories in drupal_system_listing().',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Test that files in different directories take precedence as expected.
+ */
+ function testDirectoryPrecedence() {
+ // Define the module files we will search for, and the directory precedence
+ // we expect.
+ $expected_directories = array(
+ // When the copy of the module in the profile directory is incompatible
+ // with Drupal core, the copy in the core modules directory takes
+ // precedence.
+ 'drupal_system_listing_incompatible_test' => array(
+ 'modules/simpletest/tests',
+ 'profiles/testing/modules',
+ ),
+ // When both copies of the module are compatible with Drupal core, the
+ // copy in the profile directory takes precedence.
+ 'drupal_system_listing_compatible_test' => array(
+ 'profiles/testing/modules',
+ 'modules/simpletest/tests',
+ ),
+ );
+
+ // This test relies on two versions of the same module existing in
+ // different places in the filesystem. Without that, the test has no
+ // meaning, so assert their presence first.
+ foreach ($expected_directories as $module => $directories) {
+ foreach ($directories as $directory) {
+ $filename = "$directory/$module/$module.module";
+ $this->assertTrue(file_exists(DRUPAL_ROOT . '/' . $filename), format_string('@filename exists.', array('@filename' => $filename)));
+ }
+ }
+
+ // Now scan the directories and check that the files take precedence as
+ // expected.
+ $files = drupal_system_listing('/\.module$/', 'modules', 'name', 1);
+ foreach ($expected_directories as $module => $directories) {
+ $expected_directory = array_shift($directories);
+ $expected_filename = "$expected_directory/$module/$module.module";
+ $this->assertEqual($files[$module]->uri, $expected_filename, format_string('Module @module was found at @filename.', array('@module' => $module, '@filename' => $expected_filename)));
+ }
+ }
+}
+
+/**
+ * Tests for the format_date() function.
+ */
+class FormatDateUnitTest extends DrupalWebTestCase {
+
+ /**
+ * Arbitrary langcode for a custom language.
+ */
+ const LANGCODE = 'xx';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Format date',
+ 'description' => 'Test the format_date() function.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('locale');
+ variable_set('configurable_timezones', 1);
+ variable_set('date_format_long', 'l, j. F Y - G:i');
+ variable_set('date_format_medium', 'j. F Y - G:i');
+ variable_set('date_format_short', 'Y M j - g:ia');
+ variable_set('locale_custom_strings_' . self::LANGCODE, array(
+ '' => array('Sunday' => 'domingo'),
+ 'Long month name' => array('March' => 'marzo'),
+ ));
+ $this->refreshVariables();
+ }
+
+ /**
+ * Test admin-defined formats in format_date().
+ */
+ function testAdminDefinedFormatDate() {
+ // Create an admin user.
+ $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $this->drupalLogin($this->admin_user);
+
+ // Add new date format.
+ $admin_date_format = 'j M y';
+ $edit = array('date_format' => $admin_date_format);
+ $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, 'Add format');
+
+ // Add a new date format which just differs in the case.
+ $admin_date_format_uppercase = 'j M Y';
+ $edit = array('date_format' => $admin_date_format_uppercase);
+ $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+ $this->assertText(t('Custom date format added.'));
+
+ // Add new date type.
+ $edit = array(
+ 'date_type' => 'Example Style',
+ 'machine_name' => 'example_style',
+ 'date_format' => $admin_date_format,
+ );
+ $this->drupalPost('admin/config/regional/date-time/types/add', $edit, 'Add date type');
+
+ // Add a second date format with a different case than the first.
+ $edit = array(
+ 'machine_name' => 'example_style_uppercase',
+ 'date_type' => 'Example Style Uppercase',
+ 'date_format' => $admin_date_format_uppercase,
+ );
+ $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
+ $this->assertText(t('New date type added successfully.'));
+
+ $timestamp = strtotime('2007-03-10T00:00:00+00:00');
+ $this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', 'Test format_date() using an admin-defined date type.');
+ $this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007', 'Test format_date() using an admin-defined date type with different case.');
+ $this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'medium'), 'Test format_date() defaulting to medium when $type not found.');
+ }
+
+ /**
+ * Tests for the format_date() function.
+ */
+ function testFormatDate() {
+ global $user, $language;
+
+ $timestamp = strtotime('2007-03-26T00:00:00+00:00');
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test all parameters.');
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test translated format.');
+ $this->assertIdentical(format_date($timestamp, 'custom', '\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'l, 25-Mar-07 17:00:00 PDT', 'Test an escaped format string.');
+ $this->assertIdentical(format_date($timestamp, 'custom', '\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\domingo, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash character.');
+ $this->assertIdentical(format_date($timestamp, 'custom', '\\\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\l, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash followed by escaped format string.');
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London', 'en'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
+
+ // Create an admin user and add Spanish language.
+ $admin_user = $this->drupalCreateUser(array('administer languages'));
+ $this->drupalLogin($admin_user);
+ $edit = array(
+ 'langcode' => self::LANGCODE,
+ 'name' => self::LANGCODE,
+ 'native' => self::LANGCODE,
+ 'direction' => LANGUAGE_LTR,
+ 'prefix' => self::LANGCODE,
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
+ // Create a test user to carry out the tests.
+ $test_user = $this->drupalCreateUser();
+ $this->drupalLogin($test_user);
+ $edit = array('language' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
+ $this->drupalPost('user/' . $test_user->uid . '/edit', $edit, t('Save'));
+
+ // Disable session saving as we are about to modify the global $user.
+ drupal_save_session(FALSE);
+ // Save the original user and language and then replace it with the test user and language.
+ $real_user = $user;
+ $user = user_load($test_user->uid, TRUE);
+ $real_language = $language->language;
+ $language->language = $user->language;
+ // Simulate a Drupal bootstrap with the logged-in user.
+ date_default_timezone_set(drupal_get_user_timezone());
+
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test a different language.');
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
+ $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T'), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test custom date format.');
+ $this->assertIdentical(format_date($timestamp, 'long'), 'domingo, 25. marzo 2007 - 17:00', 'Test long date format.');
+ $this->assertIdentical(format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', 'Test medium date format.');
+ $this->assertIdentical(format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', 'Test short date format.');
+ $this->assertIdentical(format_date($timestamp), '25. marzo 2007 - 17:00', 'Test default date format.');
+
+ // Restore the original user and language, and enable session saving.
+ $user = $real_user;
+ $language->language = $real_language;
+ // Restore default time zone.
+ date_default_timezone_set(drupal_get_user_timezone());
+ drupal_save_session(TRUE);
+ }
+}
+
+/**
+ * Tests for the format_date() function.
+ */
+class DrupalAttributesUnitTest extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'HTML Attributes',
+ 'description' => 'Perform unit tests on the drupal_attributes() function.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Tests that drupal_html_class() cleans the class name properly.
+ */
+ function testDrupalAttributes() {
+ // Verify that special characters are HTML encoded.
+ $this->assertIdentical(drupal_attributes(array('title' => '&"\'<>')), ' title="&amp;&quot;&#039;&lt;&gt;"', 'HTML encode attribute values.');
+
+ // Verify multi-value attributes are concatenated with spaces.
+ $attributes = array('class' => array('first', 'last'));
+ $this->assertIdentical(drupal_attributes(array('class' => array('first', 'last'))), ' class="first last"', 'Concatenate multi-value attributes.');
+
+ // Verify empty attribute values are rendered.
+ $this->assertIdentical(drupal_attributes(array('alt' => '')), ' alt=""', 'Empty attribute value #1.');
+ $this->assertIdentical(drupal_attributes(array('alt' => NULL)), ' alt=""', 'Empty attribute value #2.');
+
+ // Verify multiple attributes are rendered.
+ $attributes = array(
+ 'id' => 'id-test',
+ 'class' => array('first', 'last'),
+ 'alt' => 'Alternate',
+ );
+ $this->assertIdentical(drupal_attributes($attributes), ' id="id-test" class="first last" alt="Alternate"', 'Multiple attributes.');
+
+ // Verify empty attributes array is rendered.
+ $this->assertIdentical(drupal_attributes(array()), '', 'Empty attributes array.');
+ }
+}
+
+/**
+ * Tests converting PHP variables to JSON strings and back.
+ */
+class DrupalJSONTest extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'JSON',
+ 'description' => 'Perform unit tests on the drupal_json_encode() and drupal_json_decode() functions.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Tests converting PHP variables to JSON strings and back.
+ */
+ function testJSON() {
+ // Setup a string with the full ASCII table.
+ // @todo: Add tests for non-ASCII characters and Unicode.
+ $str = '';
+ for ($i=0; $i < 128; $i++) {
+ $str .= chr($i);
+ }
+ // Characters that must be escaped.
+ // We check for unescaped " separately.
+ $html_unsafe = array('<', '>', '\'', '&');
+ // The following are the encoded forms of: < > ' & "
+ $html_unsafe_escaped = array('\u003C', '\u003E', '\u0027', '\u0026', '\u0022');
+
+ // Verify there aren't character encoding problems with the source string.
+ $this->assertIdentical(strlen($str), 128, 'A string with the full ASCII table has the correct length.');
+ foreach ($html_unsafe as $char) {
+ $this->assertTrue(strpos($str, $char) > 0, format_string('A string with the full ASCII table includes @s.', array('@s' => $char)));
+ }
+
+ // Verify that JSON encoding produces a string with all of the characters.
+ $json = drupal_json_encode($str);
+ $this->assertTrue(strlen($json) > strlen($str), 'A JSON encoded string is larger than the source string.');
+
+ // The first and last characters should be ", and no others.
+ $this->assertTrue($json[0] == '"', 'A JSON encoded string begins with ".');
+ $this->assertTrue($json[strlen($json) - 1] == '"', 'A JSON encoded string ends with ".');
+ $this->assertTrue(substr_count($json, '"') == 2, 'A JSON encoded string contains exactly two ".');
+
+ // Verify that encoding/decoding is reversible.
+ $json_decoded = drupal_json_decode($json);
+ $this->assertIdentical($str, $json_decoded, 'Encoding a string to JSON and decoding back results in the original string.');
+
+ // Verify reversibility for structured data. Also verify that necessary
+ // characters are escaped.
+ $source = array(TRUE, FALSE, 0, 1, '0', '1', $str, array('key1' => $str, 'key2' => array('nested' => TRUE)));
+ $json = drupal_json_encode($source);
+ foreach ($html_unsafe as $char) {
+ $this->assertTrue(strpos($json, $char) === FALSE, format_string('A JSON encoded string does not contain @s.', array('@s' => $char)));
+ }
+ // Verify that JSON encoding escapes the HTML unsafe characters
+ foreach ($html_unsafe_escaped as $char) {
+ $this->assertTrue(strpos($json, $char) > 0, format_string('A JSON encoded string contains @s.', array('@s' => $char)));
+ }
+ $json_decoded = drupal_json_decode($json);
+ $this->assertNotIdentical($source, $json, 'An array encoded in JSON is not identical to the source.');
+ $this->assertIdentical($source, $json_decoded, 'Encoding structured data to JSON and decoding back results in the original data.');
+ }
+}
+
+/**
+ * Tests for RDF namespaces XML serialization.
+ */
+class DrupalGetRdfNamespacesTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'RDF namespaces XML serialization tests',
+ 'description' => 'Confirm that the serialization of RDF namespaces via drupal_get_rdf_namespaces() is output and parsed correctly in the XHTML document.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('rdf', 'rdf_test');
+ }
+
+ /**
+ * Test RDF namespaces.
+ */
+ function testGetRdfNamespaces() {
+ // Fetches the front page and extracts XML namespaces.
+ $this->drupalGet('');
+ $xml = new SimpleXMLElement($this->content);
+ $ns = $xml->getDocNamespaces();
+
+ $this->assertEqual($ns['rdfs'], 'http://www.w3.org/2000/01/rdf-schema#', 'A prefix declared once is displayed.');
+ $this->assertEqual($ns['foaf'], 'http://xmlns.com/foaf/0.1/', 'The same prefix declared in several implementations of hook_rdf_namespaces() is valid as long as all the namespaces are the same.');
+ $this->assertEqual($ns['foaf1'], 'http://xmlns.com/foaf/0.1/', 'Two prefixes can be assigned the same namespace.');
+ $this->assertTrue(!isset($ns['dc']), 'A prefix with conflicting namespaces is discarded.');
+ }
+}
+
+/**
+ * Basic tests for drupal_add_feed().
+ */
+class DrupalAddFeedTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'drupal_add_feed() tests',
+ 'description' => 'Make sure that drupal_add_feed() works correctly with various constructs.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Test drupal_add_feed() with paths, URLs, and titles.
+ */
+ function testBasicFeedAddNoTitle() {
+ $path = $this->randomName(12);
+ $external_url = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
+ $fully_qualified_local_url = url($this->randomName(12), array('absolute' => TRUE));
+
+ $path_for_title = $this->randomName(12);
+ $external_for_title = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
+ $fully_qualified_for_title = url($this->randomName(12), array('absolute' => TRUE));
+
+ // Possible permutations of drupal_add_feed() to test.
+ // - 'input_url': the path passed to drupal_add_feed(),
+ // - 'output_url': the expected URL to be found in the header.
+ // - 'title' == the title of the feed as passed into drupal_add_feed().
+ $urls = array(
+ 'path without title' => array(
+ 'input_url' => $path,
+ 'output_url' => url($path, array('absolute' => TRUE)),
+ 'title' => '',
+ ),
+ 'external URL without title' => array(
+ 'input_url' => $external_url,
+ 'output_url' => $external_url,
+ 'title' => '',
+ ),
+ 'local URL without title' => array(
+ 'input_url' => $fully_qualified_local_url,
+ 'output_url' => $fully_qualified_local_url,
+ 'title' => '',
+ ),
+ 'path with title' => array(
+ 'input_url' => $path_for_title,
+ 'output_url' => url($path_for_title, array('absolute' => TRUE)),
+ 'title' => $this->randomName(12),
+ ),
+ 'external URL with title' => array(
+ 'input_url' => $external_for_title,
+ 'output_url' => $external_for_title,
+ 'title' => $this->randomName(12),
+ ),
+ 'local URL with title' => array(
+ 'input_url' => $fully_qualified_for_title,
+ 'output_url' => $fully_qualified_for_title,
+ 'title' => $this->randomName(12),
+ ),
+ );
+
+ foreach ($urls as $description => $feed_info) {
+ drupal_add_feed($feed_info['input_url'], $feed_info['title']);
+ }
+
+ $this->drupalSetContent(drupal_get_html_head());
+ foreach ($urls as $description => $feed_info) {
+ $this->assertPattern($this->urlToRSSLinkPattern($feed_info['output_url'], $feed_info['title']), format_string('Found correct feed header for %description', array('%description' => $description)));
+ }
+ }
+
+ /**
+ * Create a pattern representing the RSS feed in the page.
+ */
+ function urlToRSSLinkPattern($url, $title = '') {
+ // Escape any regular expression characters in the URL ('?' is the worst).
+ $url = preg_replace('/([+?.*])/', '[$0]', $url);
+ $generated_pattern = '%<link +rel="alternate" +type="application/rss.xml" +title="' . $title . '" +href="' . $url . '" */>%';
+ return $generated_pattern;
+ }
+}
+
+/**
+ * Test for theme_feed_icon().
+ */
+class FeedIconTest extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Feed icon',
+ 'description' => 'Check escaping of theme_feed_icon()',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Check that special characters are correctly escaped. Test for issue #1211668.
+ */
+ function testFeedIconEscaping() {
+ $variables = array();
+ $variables['url'] = 'node';
+ $variables['title'] = '<>&"\'';
+ $text = theme_feed_icon($variables);
+ preg_match('/title="(.*?)"/', $text, $matches);
+ $this->assertEqual($matches[1], 'Subscribe to &amp;&quot;&#039;', 'theme_feed_icon() escapes reserved HTML characters.');
+ }
+
+}
+
+/**
+ * Test array diff functions.
+ */
+class ArrayDiffUnitTest extends DrupalUnitTestCase {
+
+ /**
+ * Array to use for testing.
+ *
+ * @var array
+ */
+ protected $array1;
+
+ /**
+ * Array to use for testing.
+ *
+ * @var array
+ */
+ protected $array2;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Array differences',
+ 'description' => 'Performs tests on drupal_array_diff_assoc_recursive().',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+
+ $this->array1 = array(
+ 'same' => 'yes',
+ 'different' => 'no',
+ 'array_empty_diff' => array(),
+ 'null' => NULL,
+ 'int_diff' => 1,
+ 'array_diff' => array('same' => 'same', 'array' => array('same' => 'same')),
+ 'array_compared_to_string' => array('value'),
+ 'string_compared_to_array' => 'value',
+ 'new' => 'new',
+ );
+ $this->array2 = array(
+ 'same' => 'yes',
+ 'different' => 'yes',
+ 'array_empty_diff' => array(),
+ 'null' => NULL,
+ 'int_diff' => '1',
+ 'array_diff' => array('same' => 'different', 'array' => array('same' => 'same')),
+ 'array_compared_to_string' => 'value',
+ 'string_compared_to_array' => array('value'),
+ );
+ }
+
+
+ /**
+ * Tests drupal_array_diff_assoc_recursive().
+ */
+ public function testArrayDiffAssocRecursive() {
+ $expected = array(
+ 'different' => 'no',
+ 'int_diff' => 1,
+ // The 'array' key should not be returned, as it's the same.
+ 'array_diff' => array('same' => 'same'),
+ 'array_compared_to_string' => array('value'),
+ 'string_compared_to_array' => 'value',
+ 'new' => 'new',
+ );
+
+ $this->assertIdentical(drupal_array_diff_assoc_recursive($this->array1, $this->array2), $expected);
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.css b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.css
new file mode 100644
index 0000000..b86cead
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.css
@@ -0,0 +1,2 @@
+
+/* This file is for testing CSS file inclusion, no contents are necessary. */
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.info b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.info
new file mode 100644
index 0000000..e44c56e
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.info
@@ -0,0 +1,14 @@
+name = "Common Test"
+description = "Support module for Common tests."
+package = Testing
+version = VERSION
+core = 7.x
+stylesheets[all][] = common_test.css
+stylesheets[print][] = common_test.print.css
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.module b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.module
new file mode 100644
index 0000000..674a494
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/simpletest/tests/common_test.module
@@ -0,0 +1,276 @@
+<?php
+
+/**
+ * @file
+ * Helper module for the Common tests.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function common_test_menu() {
+ $items['common-test/drupal_goto'] = array(
+ 'title' => 'Drupal Goto',
+ 'page callback' => 'common_test_drupal_goto_land',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/drupal_goto/fail'] = array(
+ 'title' => 'Drupal Goto',
+ 'page callback' => 'common_test_drupal_goto_land_fail',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/drupal_goto/redirect'] = array(
+ 'title' => 'Drupal Goto',
+ 'page callback' => 'common_test_drupal_goto_redirect',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/drupal_goto/redirect_advanced'] = array(
+ 'title' => 'Drupal Goto',
+ 'page callback' => 'common_test_drupal_goto_redirect_advanced',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/drupal_goto/redirect_fail'] = array(
+ 'title' => 'Drupal Goto Failure',
+ 'page callback' => 'drupal_goto',
+ 'page arguments' => array('common-test/drupal_goto/fail'),
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/destination'] = array(
+ 'title' => 'Drupal Get Destination',
+ 'page callback' => 'common_test_destination',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['common-test/query-string'] = array(
+ 'title' => 'Test querystring',
+ 'page callback' => 'common_test_js_and_css_querystring',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ return $items;
+}
+
+/**
+ * Redirect using drupal_goto().
+ */
+function common_test_drupal_goto_redirect() {
+ drupal_goto('common-test/drupal_goto');
+}
+
+/**
+ * Redirect using drupal_goto().
+ */
+function common_test_drupal_goto_redirect_advanced() {
+ drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
+}
+
+/**
+ * Landing page for drupal_goto().
+ */
+function common_test_drupal_goto_land() {
+ print "drupal_goto";
+}
+
+/**
+ * Fail landing page for drupal_goto().
+ */
+function common_test_drupal_goto_land_fail() {
+ print "drupal_goto_fail";
+}
+
+/**
+ * Implements hook_drupal_goto_alter().
+ */
+function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+ if ($path == 'common-test/drupal_goto/fail') {
+ $path = 'common-test/drupal_goto/redirect';
+ }
+}
+
+/**
+ * Print destination query parameter.
+ */
+function common_test_destination() {
+ $destination = drupal_get_destination();
+ print "The destination: " . check_plain($destination['destination']);
+}
+
+/**
+ * Applies #printed to an element to help test #pre_render.
+ */
+function common_test_drupal_render_printing_pre_render($elements) {
+ $elements['#printed'] = TRUE;
+ return $elements;
+}
+
+/**
+ * Implements hook_TYPE_alter().
+ */
+function common_test_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
+ // Alter first argument.
+ if (is_array($data)) {
+ $data['foo'] = 'Drupal';
+ }
+ elseif (is_object($data)) {
+ $data->foo = 'Drupal';
+ }
+ // Alter second argument, if present.
+ if (isset($arg2)) {
+ if (is_array($arg2)) {
+ $arg2['foo'] = 'Drupal';
+ }
+ elseif (is_object($arg2)) {
+ $arg2->foo = 'Drupal';
+ }
+ }
+ // Try to alter third argument, if present.
+ if (isset($arg3)) {
+ if (is_array($arg3)) {
+ $arg3['foo'] = 'Drupal';
+ }
+ elseif (is_object($arg3)) {
+ $arg3->foo = 'Drupal';
+ }
+ }
+}
+
+/**
+ * Implements hook_TYPE_alter() on behalf of Bartik theme.
+ *
+ * Same as common_test_drupal_alter_alter(), but here, we verify that themes
+ * can also alter and come last.
+ */
+function bartik_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
+ // Alter first argument.
+ if (is_array($data)) {
+ $data['foo'] .= ' theme';
+ }
+ elseif (is_object($data)) {
+ $data->foo .= ' theme';
+ }
+ // Alter second argument, if present.
+ if (isset($arg2)) {
+ if (is_array($arg2)) {
+ $arg2['foo'] .= ' theme';
+ }
+ elseif (is_object($arg2)) {
+ $arg2->foo .= ' theme';
+ }
+ }
+ // Try to alter third argument, if present.
+ if (isset($arg3)) {
+ if (is_array($arg3)) {
+ $arg3['foo'] .= ' theme';
+ }
+ elseif (is_object($arg3)) {
+ $arg3->foo .= ' theme';
+ }
+ }
+}
+
+/**